From 42107150703ad46e55f19dd66e0c0fb2b5140b96 Mon Sep 17 00:00:00 2001 From: losfair Date: Sat, 7 Sep 2019 01:31:16 +0800 Subject: [PATCH 001/342] AArch64 translation module. --- lib/singlepass-backend/Cargo.toml | 4 +- lib/singlepass-backend/src/lib.rs | 6 +- .../src/translator_aarch64.rs | 601 ++++++++++++++++++ 3 files changed, 607 insertions(+), 4 deletions(-) create mode 100644 lib/singlepass-backend/src/translator_aarch64.rs diff --git a/lib/singlepass-backend/Cargo.toml b/lib/singlepass-backend/Cargo.toml index af1dbe43782..87eb6e6e4eb 100644 --- a/lib/singlepass-backend/Cargo.toml +++ b/lib/singlepass-backend/Cargo.toml @@ -11,8 +11,8 @@ readme = "README.md" [dependencies] wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" } wasmparser = "0.35.1" -dynasm = "0.3.2" -dynasmrt = "0.3.1" +dynasm = "0.5.0" +dynasmrt = "0.5.0" lazy_static = "1.3.0" byteorder = "1.3.2" nix = "0.15.0" diff --git a/lib/singlepass-backend/src/lib.rs b/lib/singlepass-backend/src/lib.rs index ccea7502ee9..59469916b25 100644 --- a/lib/singlepass-backend/src/lib.rs +++ b/lib/singlepass-backend/src/lib.rs @@ -1,4 +1,4 @@ -#![deny( +/*#![deny( dead_code, nonstandard_style, unused_imports, @@ -6,7 +6,7 @@ unused_variables, unused_unsafe, unreachable_patterns -)] +)]*/ #![feature(proc_macro_hygiene)] #![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")] #![doc(html_logo_url = "https://avatars3.githubusercontent.com/u/44205449?s=200&v=4")] @@ -14,6 +14,7 @@ #[cfg(not(any( all(target_os = "macos", target_arch = "x86_64"), all(target_os = "linux", target_arch = "x86_64"), + all(target_os = "linux", target_arch = "aarch64"), )))] compile_error!("This crate doesn't yet support compiling on operating systems other than linux and macos and architectures other than x86_64"); @@ -30,6 +31,7 @@ extern crate byteorder; extern crate smallvec; mod codegen_x64; +mod translator_aarch64; mod emitter_x64; mod machine; pub mod protect_unix; diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs new file mode 100644 index 00000000000..8d23a7fd83a --- /dev/null +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -0,0 +1,601 @@ +use crate::codegen_x64::*; +use crate::emitter_x64::*; +use dynasmrt::{aarch64::Assembler, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi}; + +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +pub struct AX(pub u32); + +impl AX { + pub fn x(&self) -> u32 { self.0 } +} + +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +pub struct AV(pub u32); + +impl AV { + pub fn v(&self) -> u32 { self.0 } +} + +/* +#[repr(u8)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum GPR { + RAX, + RCX, + RDX, + RBX, + RSP, + RBP, + RSI, + RDI, + R8, + R9, + R10, + R11, + R12, + R13, + R14, + R15, +} + +#[repr(u8)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum XMM { + XMM0, + XMM1, + XMM2, + XMM3, + XMM4, + XMM5, + XMM6, + XMM7, +} +*/ + +fn map_gpr(gpr: GPR) -> AX { + use GPR::*; + + match gpr { + RAX => AX(0), + RCX => AX(1), + RDX => AX(2), + RBX => AX(3), + RSP => AX(4), + RBP => AX(5), + RSI => AX(6), + RDI => AX(7), + R8 => AX(8), + R9 => AX(9), + R10 => AX(10), + R11 => AX(11), + R12 => AX(12), + R13 => AX(13), + R14 => AX(14), + R15 => AX(15), + } +} + +fn map_xmm(xmm: XMM) -> AV { + use XMM::*; + + match xmm { + XMM0 => AV(0), + XMM1 => AV(1), + XMM2 => AV(2), + XMM3 => AV(3), + XMM4 => AV(4), + XMM5 => AV(5), + XMM6 => AV(6), + XMM7 => AV(7), + } +} + +pub fn get_aarch64_assembler() -> Assembler { + let mut a = Assembler::new().unwrap(); + dynasm!( + a + ; .arch aarch64 + ; .alias x_rsp, x28 + ; .alias x_tmp1, x27 + ; .alias w_tmp1, w27 + ; .alias x_tmp2, x26 + ; .alias w_tmp2, w26 + ); + a +} + +macro_rules! binop_imm32_gpr { + ($ins:ident, $assembler:tt, $sz:expr, $src:expr, $dst:expr, $otherwise:block) => { + match ($sz, $src, $dst) { + (Size::S32, Location::Imm32(src), Location::GPR(dst)) => { + dynasm!($assembler + ; b >after + ; data: + ; .dword src as i32 + ; after: + ; ldr w_tmp1, { + dynasm!($assembler + ; b >after + ; data: + ; .qword src as i64 + ; after: + ; ldr x_tmp1, $otherwise + } + }; +} + +macro_rules! binop_imm32_mem { + ($ins:ident, $assembler:tt, $sz:expr, $src:expr, $dst:expr, $otherwise:block) => { + match ($sz, $src, $dst) { + (Size::S32, Location::Imm32(src), Location::Memory(dst, disp)) => { + assert!(disp >= 0); + dynasm!($assembler + ; b >after + ; data: + ; .dword src as i32 + ; after: + ; ldr w_tmp1, { + assert!(disp >= 0); + dynasm!($assembler + ; b >after + ; data: + ; .qword src as i64 + ; after: + ; ldr x_tmp1, $otherwise + } + }; +} + +macro_rules! binop_imm64_gpr { + ($ins:ident, $assembler:tt, $sz:expr, $src:expr, $dst:expr, $otherwise:block) => { + match ($sz, $src, $dst) { + (Size::S64, Location::Imm64(src), Location::GPR(dst)) => { + dynasm!($assembler + ; b >after + ; data: + ; .qword src as i64 + ; after: + ; ldr x_tmp1, $otherwise + } + }; +} + +macro_rules! binop_gpr_gpr { + ($ins:ident, $assembler:tt, $sz:expr, $src:expr, $dst:expr, $otherwise:block) => { + match ($sz, $src, $dst) { + (Size::S32, Location::GPR(src), Location::GPR(dst)) => { + dynasm!($assembler + ; $ins W(map_gpr(dst).x()), W(map_gpr(dst).x()), W(map_gpr(src).x()) + ); + }, + (Size::S64, Location::GPR(src), Location::GPR(dst)) => { + dynasm!($assembler + ; $ins X(map_gpr(dst).x()), X(map_gpr(dst).x()), X(map_gpr(src).x()) + ); + }, + _ => $otherwise + } + }; +} + +macro_rules! binop_gpr_mem { + ($ins:ident, $assembler:tt, $sz:expr, $src:expr, $dst:expr, $otherwise:block) => { + match ($sz, $src, $dst) { + (Size::S32, Location::GPR(src), Location::Memory(dst, disp)) => { + dynasm!($assembler + ; ldr w_tmp1, [X(map_gpr(dst).x()), disp as u32] + ; $ins w_tmp1, w_tmp1, W(map_gpr(src).x()) + ; str w_tmp1, [X(map_gpr(dst).x()), disp as u32] + ); + }, + (Size::S64, Location::GPR(src), Location::Memory(dst, disp)) => { + dynasm!($assembler + ; ldr x_tmp1, [X(map_gpr(dst).x()), disp as u32] + ; $ins x_tmp1, x_tmp1, X(map_gpr(src).x()) + ; str x_tmp1, [X(map_gpr(dst).x()), disp as u32] + ); + }, + _ => $otherwise + } + }; +} + +macro_rules! binop_mem_gpr { + ($ins:ident, $assembler:tt, $sz:expr, $src:expr, $dst:expr, $otherwise:block) => { + match ($sz, $src, $dst) { + (Size::S32, Location::Memory(src, disp), Location::GPR(dst)) => { + dynasm!($assembler + ; ldr w_tmp1, [X(map_gpr(src).x()), disp as u32] + ; $ins W(map_gpr(dst).x()), W(map_gpr(dst).x()), w_tmp1 + ) + }, + (Size::S64, Location::Memory(src, disp), Location::GPR(dst)) => { + dynasm!($assembler + ; ldr x_tmp1, [X(map_gpr(src).x()), disp as u32] + ; $ins X(map_gpr(dst).x()), X(map_gpr(dst).x()), x_tmp1 + ) + }, + _ => $otherwise + } + }; +} + +macro_rules! binop_all_nofp { + ($ins:ident, $assembler:tt, $sz:expr, $src:expr, $dst:expr, $otherwise:block) => { + binop_imm32_gpr!($ins, $assembler, $sz, $src, $dst, { + binop_imm32_mem!($ins, $assembler, $sz, $src, $dst, { + binop_gpr_gpr!($ins, $assembler, $sz, $src, $dst, { + binop_gpr_mem!($ins, $assembler, $sz, $src, $dst, { + binop_mem_gpr!($ins, $assembler, $sz, $src, $dst, $otherwise) + }) + }) + }) + }) + }; +} + +impl Emitter for Assembler { + type Label = DynamicLabel; + type Offset = AssemblyOffset; + + fn get_label(&mut self) -> DynamicLabel { + self.new_dynamic_label() + } + + fn get_offset(&self) -> AssemblyOffset { + self.offset() + } + + fn emit_u64(&mut self, x: u64) { + self.push_u64(x); + } + + fn emit_label(&mut self, label: Self::Label) { + dynasm!(self ; => label); + } + + fn emit_nop(&mut self) { + dynasm!(self ; nop); + } + + fn emit_mov(&mut self, sz: Size, src: Location, dst: Location) { + match (sz, src, dst) { + (Size::S32, Location::GPR(src), Location::GPR(dst)) => { + dynasm!(self ; mov W(map_gpr(dst).x()), W(map_gpr(src).x())); + } + (Size::S32, Location::Memory(src, disp), Location::GPR(dst)) => { + assert!(disp >= 0); + dynasm!(self ; ldr W(map_gpr(dst).x()), [ X(map_gpr(src).x()), disp as u32 ] ); + } + (Size::S32, Location::GPR(src), Location::Memory(dst, disp)) => { + assert!(disp >= 0); + dynasm!(self ; str W(map_gpr(src).x()), [ X(map_gpr(dst).x()), disp as u32 ] ); + } + (Size::S32, Location::Imm32(x), Location::GPR(dst)) => { + dynasm!(self ; b >after; data: ; .dword x as i32; after: ; ldr W(map_gpr(dst).x()), { + dynasm!(self ; mov X(map_gpr(dst).x()), X(map_gpr(src).x())); + } + (Size::S64, Location::Memory(src, disp), Location::GPR(dst)) => { + assert!(disp >= 0); + dynasm!(self ; ldr X(map_gpr(dst).x()), [ X(map_gpr(src).x()), disp as u32 ] ); + } + (Size::S64, Location::GPR(src), Location::Memory(dst, disp)) => { + assert!(disp >= 0); + dynasm!(self ; str X(map_gpr(src).x()), [ X(map_gpr(dst).x()), disp as u32 ] ); + } + (Size::S64, Location::Imm32(x), Location::GPR(dst)) => { + dynasm!(self ; b >after; data: ; .qword x as i64; after: ; ldr X(map_gpr(dst).x()), unimplemented!() + } + } + + fn emit_lea(&mut self, sz: Size, src: Location, dst: Location) { + match (sz, src, dst) { + (Size::S32, Location::Memory(src, disp), Location::GPR(dst)) => { + dynasm!(self ; add W(map_gpr(dst).x()), W(map_gpr(src).x()), disp as u32); + } + (Size::S64, Location::Memory(src, disp), Location::GPR(dst)) => { + dynasm!(self ; add X(map_gpr(dst).x()), X(map_gpr(src).x()), disp as u32); + } + _ => unreachable!(), + } + } + fn emit_lea_label(&mut self, label: Self::Label, dst: Location) { + match dst { + Location::GPR(dst) => { + dynasm!(self ; adr X(map_gpr(dst).x()), =>label); + } + _ => unreachable!() + } + } + + fn emit_cdq(&mut self) { unimplemented!("cdq"); } + fn emit_cqo(&mut self) { unimplemented!("cqo"); } + fn emit_xor(&mut self, sz: Size, src: Location, dst: Location) { + binop_all_nofp!(eor, self, sz, src, dst, { unreachable!("xor") }); + } + fn emit_jmp(&mut self, condition: Condition, label: Self::Label) { + use Condition::*; + + match condition { + None => dynasm!(self ; b =>label), + Above => dynasm!(self ; b.hi =>label), + AboveEqual => dynasm!(self ; b.hs =>label), + Below => dynasm!(self ; b.lo =>label), + BelowEqual => dynasm!(self ; b.ls =>label), + Greater => dynasm!(self ; b.gt =>label), + GreaterEqual => dynasm!(self ; b.ge =>label), + Less => dynasm!(self ; b.lt =>label), + LessEqual => dynasm!(self ; b.le =>label), + Equal => dynasm!(self ; b.eq =>label), + NotEqual => dynasm!(self ; b.ne =>label), + Signed => dynasm!(self ; b.vs =>label), // TODO: Review this + } + } + + fn emit_jmp_location(&mut self, loc: Location) { + match loc { + Location::GPR(x) => dynasm!(self ; br X(map_gpr(x).x())), + Location::Memory(base, disp) => { + assert!(disp >= 0); + dynasm!(self ; ldr x_tmp1, [ X(map_gpr(base).x()), disp as u32 ]; br x_tmp1); + }, + _ => unreachable!(), + } + } + + fn emit_conditional_trap(&mut self, condition: Condition) { + use Condition::*; + + match condition { + None => dynasm!(self ; b >fail), + Above => dynasm!(self ; b.hi >fail), + AboveEqual => dynasm!(self ; b.hs >fail), + Below => dynasm!(self ; b.lo >fail), + BelowEqual => dynasm!(self ; b.ls >fail), + Greater => dynasm!(self ; b.gt >fail), + GreaterEqual => dynasm!(self ; b.ge >fail), + Less => dynasm!(self ; b.lt >fail), + LessEqual => dynasm!(self ; b.le >fail), + Equal => dynasm!(self ; b.eq >fail), + NotEqual => dynasm!(self ; b.ne >fail), + Signed => dynasm!(self ; b.vs >fail), // TODO: Review this + } + dynasm!( + self + ; b >ok + ; fail: + ; brk 0 + ; ok: + ); + } + + fn emit_set(&mut self, condition: Condition, dst: GPR) { unimplemented!("instruction") } + + fn emit_push(&mut self, sz: Size, src: Location) { + match (sz, src) { + (Size::S64, Location::Imm32(src)) => dynasm!(self + ; b >after + ; data: + ; .dword src as i32 + ; after: + ; ldr w_tmp1, dynasm!(self + ; sub x_rsp, x_rsp, 8 + ; str X(map_gpr(src).x()), [x_rsp] + ), + (Size::S64, Location::Memory(src, disp)) => { + assert!(disp >= 0); + dynasm!(self + ; ldr x_tmp1, [X(map_gpr(src).x()), disp as u32] + ; sub x_rsp, x_rsp, 8 + ; str x_tmp1, [x_rsp] + ); + } + _ => panic!("push {:?} {:?}", sz, src), + } + } + fn emit_pop(&mut self, sz: Size, dst: Location) { + match (sz, dst) { + (Size::S64, Location::GPR(dst)) => dynasm!(self + ; ldr X(map_gpr(dst).x()), [x_rsp] + ; add x_rsp, x_rsp, 8 + ), + (Size::S64, Location::Memory(dst, disp)) => { + assert!(disp >= 0); + dynasm!(self + ; ldr x_tmp1, [x_rsp] + ; add x_rsp, x_rsp, 8 + ; str x_tmp1, [X(map_gpr(dst).x()), disp as u32] + ); + } + _ => panic!("pop {:?} {:?}", sz, dst), + } + } + fn emit_cmp(&mut self, sz: Size, left: Location, right: Location) { unimplemented!("instruction") } + fn emit_add(&mut self, sz: Size, src: Location, dst: Location) { + binop_all_nofp!(add, self, sz, src, dst, { unreachable!("add") }); + } + fn emit_sub(&mut self, sz: Size, src: Location, dst: Location) { + binop_all_nofp!(sub, self, sz, src, dst, { unreachable!("sub") }); + } + + fn emit_imul(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_imul_imm32_gpr64(&mut self, src: u32, dst: GPR) { unimplemented!("instruction") } + + fn emit_div(&mut self, sz: Size, divisor: Location) { unimplemented!("instruction") } + fn emit_idiv(&mut self, sz: Size, divisor: Location) { unimplemented!("instruction") } + fn emit_shl(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_shr(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_sar(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_rol(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_ror(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_and(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_or(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_tzcnt(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_popcnt(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_movzx(&mut self, sz_src: Size, src: Location, sz_dst: Size, dst: Location) { unimplemented!("instruction") } + fn emit_movsx(&mut self, sz_src: Size, src: Location, sz_dst: Size, dst: Location) { unimplemented!("instruction") } + + fn emit_btc_gpr_imm8_32(&mut self, src: u8, dst: GPR) { unimplemented!("instruction") } + fn emit_btc_gpr_imm8_64(&mut self, src: u8, dst: GPR) { unimplemented!("instruction") } + + fn emit_cmovae_gpr_32(&mut self, src: GPR, dst: GPR) { unimplemented!("instruction") } + fn emit_cmovae_gpr_64(&mut self, src: GPR, dst: GPR) { unimplemented!("instruction") } + + fn emit_vaddss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vaddsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vsubss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vsubsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vmulss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vmulsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vdivss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vdivsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vmaxss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vmaxsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vminss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vminsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_vcmpeqss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vcmpeqsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_vcmpneqss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vcmpneqsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_vcmpltss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vcmpltsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_vcmpless(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vcmplesd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_vcmpgtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vcmpgtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_vcmpgess(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vcmpgesd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_vsqrtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vsqrtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_vroundss_nearest(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vroundss_floor(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vroundss_ceil(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vroundss_trunc(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vroundsd_nearest(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vroundsd_floor(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vroundsd_ceil(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vroundsd_trunc(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_vcvtss2sd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vcvtsd2ss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_ucomiss(&mut self, src: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_ucomisd(&mut self, src: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_cvttss2si_32(&mut self, src: XMMOrMemory, dst: GPR) { unimplemented!("instruction") } + fn emit_cvttss2si_64(&mut self, src: XMMOrMemory, dst: GPR) { unimplemented!("instruction") } + fn emit_cvttsd2si_32(&mut self, src: XMMOrMemory, dst: GPR) { unimplemented!("instruction") } + fn emit_cvttsd2si_64(&mut self, src: XMMOrMemory, dst: GPR) { unimplemented!("instruction") } + + fn emit_vcvtsi2ss_32(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vcvtsi2ss_64(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vcvtsi2sd_32(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vcvtsi2sd_64(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_test_gpr_64(&mut self, reg: GPR) { unimplemented!("instruction") } + + fn emit_ud2(&mut self) { dynasm!(self ; brk 2) } + fn emit_ret(&mut self) { + dynasm!(self + ; ldr x_tmp1, [x_rsp] + ; add x_rsp, x_rsp, 8 + ; br x_tmp1 + ); + } + fn emit_call_label(&mut self, label: Self::Label) { + dynasm!(self + ; b >after + ; addr: + ; .qword =>label // Is this the offset? + ; after: + + // Calculate the target address. + ; ldr x_tmp1, done + ; str x_tmp2, [x_rsp] + + // Jump. + ; br x_tmp1 + ; done: + ); + } + fn emit_call_location(&mut self, loc: Location) { + match loc { + Location::GPR(x) => dynasm!(self + // Push return address. + ; sub x_rsp, x_rsp, 8 + ; adr x_tmp1, >done + ; str x_tmp1, [x_rsp] + + // Jump. + ; br X(map_gpr(x).x()) + ; done: + ), + Location::Memory(base, disp) => { + assert!(disp >= 0); + dynasm!(self + // Push return address. + ; sub x_rsp, x_rsp, 8 + ; adr x_tmp1, >done + ; str x_tmp1, [x_rsp] + + // Read memory. + ; ldr x_tmp1, [X(map_gpr(base).x()), disp as u32] + + // Jump. + ; br x_tmp1 + ; done: + ); + }, + _ => unreachable!(), + } + } + + fn emit_bkpt(&mut self) { dynasm!(self ; brk 1) } +} From ce7c903c23792a5ee52b69658575d95242a801b5 Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 11 Sep 2019 01:13:52 +0800 Subject: [PATCH 002/342] Add impl for more instructions for aarch64 translator. --- .../src/translator_aarch64.rs | 167 +++++++++++++++++- 1 file changed, 160 insertions(+), 7 deletions(-) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 8d23a7fd83a..3b39c4f5195 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -336,8 +336,46 @@ impl Emitter for Assembler { } } - fn emit_cdq(&mut self) { unimplemented!("cdq"); } - fn emit_cqo(&mut self) { unimplemented!("cqo"); } + fn emit_cdq(&mut self) { + dynasm!( + self + ; b >after + ; bit_tester: + ; .dword 0x80000000u32 as i32 + ; all_ones: + ; .dword 0xffffffffu32 as i32 + ; after: + ; ldr w_tmp1, zero + ; not_zero: + ; ldr W(map_gpr(GPR::RDX).x()), after + ; zero: + ; mov W(map_gpr(GPR::RDX).x()), wzr + ; after: + ); + } + fn emit_cqo(&mut self) { + dynasm!( + self + ; b >after + ; bit_tester: + ; .qword 0x8000000000000000u64 as i64 + ; all_ones: + ; .qword 0xffffffffffffffffu64 as i64 + ; after: + ; ldr x_tmp1, zero + ; not_zero: + ; ldr X(map_gpr(GPR::RDX).x()), after + ; zero: + ; mov X(map_gpr(GPR::RDX).x()), xzr + ; after: + ); + } fn emit_xor(&mut self, sz: Size, src: Location, dst: Location) { binop_all_nofp!(eor, self, sz, src, dst, { unreachable!("xor") }); } @@ -397,7 +435,32 @@ impl Emitter for Assembler { ); } - fn emit_set(&mut self, condition: Condition, dst: GPR) { unimplemented!("instruction") } + fn emit_set(&mut self, condition: Condition, dst: GPR) { + use Condition::*; + + match condition { + None => dynasm!(self ; b >set), + Above => dynasm!(self ; b.hi >set), + AboveEqual => dynasm!(self ; b.hs >set), + Below => dynasm!(self ; b.lo >set), + BelowEqual => dynasm!(self ; b.ls >set), + Greater => dynasm!(self ; b.gt >set), + GreaterEqual => dynasm!(self ; b.ge >set), + Less => dynasm!(self ; b.lt >set), + LessEqual => dynasm!(self ; b.le >set), + Equal => dynasm!(self ; b.eq >set), + NotEqual => dynasm!(self ; b.ne >set), + Signed => dynasm!(self ; b.vs >set), // TODO: Review this + } + dynasm!( + self + ; mov W(map_gpr(dst).x()), wzr + ; b >ok + ; set: + ; mov W(map_gpr(dst).x()), 1 + ; ok: + ); + } fn emit_push(&mut self, sz: Size, src: Location) { match (sz, src) { @@ -442,7 +505,83 @@ impl Emitter for Assembler { _ => panic!("pop {:?} {:?}", sz, dst), } } - fn emit_cmp(&mut self, sz: Size, left: Location, right: Location) { unimplemented!("instruction") } + fn emit_cmp(&mut self, sz: Size, left: Location, right: Location) { + match (sz, left, right) { + (Size::S32, Location::Imm32(left), Location::GPR(right)) => { + dynasm!(self + ; b >after + ; data: + ; .dword left as i32 + ; after: + ; ldr w_tmp1, { + dynasm!(self + ; b >after + ; data: + ; .qword left as i64 + ; after: + ; ldr x_tmp1, { + assert!(disp >= 0); + dynasm!(self + ; b >after + ; data: + ; .dword left as i32 + ; after: + ; ldr w_tmp1, { + assert!(disp >= 0); + dynasm!(self + ; b >after + ; data: + ; .qword left as i64 + ; after: + ; ldr x_tmp1, dynasm!( + self + ; cmp W(map_gpr(right).x()), W(map_gpr(left).x()) + ), + (Size::S64, Location::GPR(left), Location::GPR(right)) => dynasm!( + self + ; cmp X(map_gpr(right).x()), X(map_gpr(left).x()) + ), + (Size::S32, Location::GPR(left), Location::Memory(right, disp)) => dynasm!( + self + ; ldr w_tmp1, [X(map_gpr(right).x()), disp as u32] + ; cmp w_tmp1, W(map_gpr(left).x()) + ), + (Size::S64, Location::GPR(left), Location::Memory(right, disp)) => dynasm!( + self + ; ldr x_tmp1, [X(map_gpr(right).x()), disp as u32] + ; cmp x_tmp1, X(map_gpr(left).x()) + ), + (Size::S32, Location::Memory(left, disp), Location::GPR(right)) => dynasm!( + self + ; ldr w_tmp1, [X(map_gpr(left).x()), disp as u32] + ; cmp W(map_gpr(right).x()), w_tmp1 + ), + (Size::S64, Location::Memory(left, disp), Location::GPR(right)) => dynasm!( + self + ; ldr x_tmp1, [X(map_gpr(left).x()), disp as u32] + ; cmp X(map_gpr(right).x()), x_tmp1 + ), + _ => unreachable!() + } + } fn emit_add(&mut self, sz: Size, src: Location, dst: Location) { binop_all_nofp!(add, self, sz, src, dst, { unreachable!("add") }); } @@ -450,9 +589,23 @@ impl Emitter for Assembler { binop_all_nofp!(sub, self, sz, src, dst, { unreachable!("sub") }); } - fn emit_imul(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } - fn emit_imul_imm32_gpr64(&mut self, src: u32, dst: GPR) { unimplemented!("instruction") } - + fn emit_imul(&mut self, sz: Size, src: Location, dst: Location) { + binop_gpr_gpr!(mul, self, sz, src, dst, { + binop_mem_gpr!(mul, self, sz, src, dst, { unreachable!() }) + }); + } + fn emit_imul_imm32_gpr64(&mut self, src: u32, dst: GPR) { + dynasm!( + self + ; b >after + ; data: + ; .dword src as i32 + ; after: + ; ldr w_tmp1, Date: Sun, 15 Sep 2019 17:57:40 +0800 Subject: [PATCH 003/342] More instructions & aarch64 trampolines. --- Cargo.lock | 85 ++-- examples/fib.wat | 20 + lib/singlepass-backend/src/codegen_x64.rs | 70 ++- lib/singlepass-backend/src/lib.rs | 2 +- .../src/translator_aarch64.rs | 420 +++++++++++++----- 5 files changed, 443 insertions(+), 154 deletions(-) create mode 100644 examples/fib.wat diff --git a/Cargo.lock b/Cargo.lock index 9746f992237..f0f7b3014ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -90,7 +90,7 @@ dependencies = [ "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)", "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 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)", "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 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", @@ -120,7 +120,7 @@ name = "bstr" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 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)", "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.99 (registry+https://github.com/rust-lang/crates.io-index)", @@ -136,7 +136,7 @@ name = "c2-chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 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)", "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -260,7 +260,7 @@ name = "colored" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 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)", "winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -325,7 +325,7 @@ dependencies = [ "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)", - "lazy_static 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.62 (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)", @@ -367,7 +367,7 @@ 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)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 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)", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -386,7 +386,7 @@ 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)", - "lazy_static 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)", ] [[package]] @@ -428,26 +428,25 @@ dependencies = [ [[package]] name = "dynasm" -version = "0.3.2" +version = "0.5.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)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "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)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.1 (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.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "dynasmrt" -version = "0.3.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -640,7 +639,7 @@ dependencies = [ "either 1.5.2 (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.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.62 (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.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -705,7 +704,7 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -728,7 +727,7 @@ version = "80.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -758,15 +757,6 @@ dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -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)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "memmap" version = "0.7.0" @@ -836,7 +826,7 @@ dependencies = [ [[package]] name = "owning_ref" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1049,7 +1039,7 @@ dependencies = [ "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-queue 0.1.2 (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.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)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1300,11 +1290,6 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "take_mut" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "target-lexicon" version = "0.4.0" @@ -1349,7 +1334,7 @@ name = "thread_local" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 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)", ] [[package]] @@ -1399,7 +1384,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" 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.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)", "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "typetag-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1577,7 +1562,7 @@ name = "wasmer-emscripten" version = "0.6.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 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.62 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1615,7 +1600,7 @@ dependencies = [ "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "inkwell 0.1.0 (git+https://github.com/wasmerio/inkwell?branch=llvm8-0)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1653,7 +1638,7 @@ name = "wasmer-runtime" version = "0.6.0" dependencies = [ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 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)", "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.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1686,7 +1671,7 @@ dependencies = [ "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.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 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.62 (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)", @@ -1707,9 +1692,9 @@ version = "0.6.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "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.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dynasm 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dynasmrt 0.5.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)", "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)", @@ -1838,7 +1823,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 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)", "rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1890,8 +1875,8 @@ dependencies = [ "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 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 dynasm 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56607fba702a46df49ce4f6e1e7b7cc55df2c8c5066630a1b4e91939f8948795" +"checksum dynasmrt 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81c856c0e3505b907e0f07a70712daf717a204e8195e3f41d20badea3718762c" "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" @@ -1922,14 +1907,13 @@ dependencies = [ "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "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.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" +"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" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" -"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" "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" @@ -1938,7 +1922,7 @@ dependencies = [ "checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "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 owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" "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" @@ -1995,7 +1979,6 @@ dependencies = [ "checksum syn 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "158521e6f544e7e3dcfc370ac180794aa38cb34a1b1e07609376d4adcf429b93" "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 take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b0ab4982b8945c35cc1c46a83a9094c414f6828a099ce5dcaa8ee2b04642dcb" "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" diff --git a/examples/fib.wat b/examples/fib.wat new file mode 100644 index 00000000000..a797fdae484 --- /dev/null +++ b/examples/fib.wat @@ -0,0 +1,20 @@ +(module + (func $main (result i32) + (call $fib (i32.const 40)) + ) + + (func $fib (param $n i32) (result i32) + (if (i32.eq (get_local $n) (i32.const 0)) + (then (return (i32.const 1))) + ) + (if (i32.eq (get_local $n) (i32.const 1)) + (then (return (i32.const 1))) + ) + (i32.add + (call $fib (i32.sub (get_local $n) (i32.const 1))) + (call $fib (i32.sub (get_local $n) (i32.const 2))) + ) + ) + + (export "main" (func $main)) +) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index e069dfeeb0a..708339e6a81 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -4,7 +4,11 @@ use crate::emitter_x64::*; use crate::machine::*; use crate::protect_unix; -use dynasmrt::{x64::Assembler, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi}; +#[cfg(target_arch = "aarch64")] +use dynasmrt::aarch64::Assembler; +#[cfg(target_arch = "x86_64")] +use dynasmrt::x64::Assembler; +use dynasmrt::{AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi}; use smallvec::SmallVec; use std::ptr::NonNull; use std::{ @@ -36,6 +40,7 @@ use wasmer_runtime_core::{ }; use wasmparser::{Operator, Type as WpType, TypeOrFuncType as WpTypeOrFuncType}; +#[cfg(target_arch = "x86_64")] lazy_static! { /// Performs a System V call to `target` with [stack_top..stack_base] as the argument list, from right to left. static ref CONSTRUCT_STACK_AND_CALL_WASM: unsafe extern "C" fn (stack_top: *const u64, stack_base: *const u64, ctx: *mut vm::Ctx, target: *const vm::Func) -> u64 = { @@ -124,6 +129,69 @@ lazy_static! { }; } +#[cfg(target_arch = "aarch64")] +lazy_static! { + /// Performs a System V call to `target` with [stack_top..stack_base] as the argument list, from right to left. + static ref CONSTRUCT_STACK_AND_CALL_WASM: unsafe extern "C" fn (stack_top: *const u64, stack_base: *const u64, ctx: *mut vm::Ctx, target: *const vm::Func) -> u64 = { + let mut assembler = Assembler::new().unwrap(); + let offset = assembler.offset(); + dynasm!( + assembler + ; .arch aarch64 + ; sub sp, sp, 80 + ; str x19, [sp, 0] + ; str x20, [sp, 8] + ; str x21, [sp, 16] + ; str x22, [sp, 24] + ; str x23, [sp, 32] + ; str x24, [sp, 40] + ; str x25, [sp, 48] + ; str x26, [sp, 56] + ; str x27, [sp, 64] + ; str x28, [sp, 72] + ; mov x28, sp // WASM stack pointer + ; ldr x9, >v_65536 + ; sub sp, sp, x9 // Pre-allocate the WASM stack + + // return address + ; adr x9, >done + ; sub x28, x28, 8 + ; str x9, [x28] // Keep this consistent with RSP mapping in translator_aarch64 + + // ctx + ; mov X(crate::translator_aarch64::map_gpr(GPR::RDI).x()), x2 + + // TODO: params + + // Jump to target function! + ; br x3 + + ; done: + ; ldr x9, >v_65536 + ; add sp, sp, x9 // Resume stack pointer + ; ldr x19, [sp, 0] + ; ldr x20, [sp, 8] + ; ldr x21, [sp, 16] + ; ldr x22, [sp, 24] + ; ldr x23, [sp, 32] + ; ldr x24, [sp, 40] + ; ldr x25, [sp, 48] + ; ldr x26, [sp, 56] + ; ldr x27, [sp, 64] + ; ldr x28, [sp, 72] + ; add sp, sp, 80 + ; br x30 // LR + + ; v_65536: + ; .qword 65536 + ); + let buf = assembler.finalize().unwrap(); + let ret = unsafe { ::std::mem::transmute(buf.ptr(offset)) }; + ::std::mem::forget(buf); + ret + }; +} + pub struct X64ModuleCodeGenerator { functions: Vec, signatures: Option>>, diff --git a/lib/singlepass-backend/src/lib.rs b/lib/singlepass-backend/src/lib.rs index 59469916b25..f88f1e8fa4d 100644 --- a/lib/singlepass-backend/src/lib.rs +++ b/lib/singlepass-backend/src/lib.rs @@ -31,10 +31,10 @@ extern crate byteorder; extern crate smallvec; mod codegen_x64; -mod translator_aarch64; mod emitter_x64; mod machine; pub mod protect_unix; +mod translator_aarch64; pub use codegen_x64::X64FunctionCode as FunctionCodeGenerator; pub use codegen_x64::X64ModuleCodeGenerator as ModuleCodeGenerator; diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 3b39c4f5195..6d7d699e18f 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + use crate::codegen_x64::*; use crate::emitter_x64::*; use dynasmrt::{aarch64::Assembler, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi}; @@ -6,14 +8,18 @@ use dynasmrt::{aarch64::Assembler, AssemblyOffset, DynamicLabel, DynasmApi, Dyna pub struct AX(pub u32); impl AX { - pub fn x(&self) -> u32 { self.0 } + pub fn x(&self) -> u32 { + self.0 + } } #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] pub struct AV(pub u32); impl AV { - pub fn v(&self) -> u32 { self.0 } + pub fn v(&self) -> u32 { + self.0 + } } /* @@ -52,7 +58,7 @@ pub enum XMM { } */ -fn map_gpr(gpr: GPR) -> AX { +pub fn map_gpr(gpr: GPR) -> AX { use GPR::*; match gpr { @@ -60,7 +66,7 @@ fn map_gpr(gpr: GPR) -> AX { RCX => AX(1), RDX => AX(2), RBX => AX(3), - RSP => AX(4), + RSP => AX(28), RBP => AX(5), RSI => AX(6), RDI => AX(7), @@ -75,7 +81,7 @@ fn map_gpr(gpr: GPR) -> AX { } } -fn map_xmm(xmm: XMM) -> AV { +pub fn map_xmm(xmm: XMM) -> AV { use XMM::*; match xmm { @@ -312,10 +318,10 @@ impl Emitter for Assembler { (Size::S64, Location::Imm32(x), Location::GPR(dst)) => { dynasm!(self ; b >after; data: ; .qword x as i64; after: ; ldr X(map_gpr(dst).x()), unimplemented!() + _ => unimplemented!(), } } - + fn emit_lea(&mut self, sz: Size, src: Location, dst: Location) { match (sz, src, dst) { (Size::S32, Location::Memory(src, disp), Location::GPR(dst)) => { @@ -332,10 +338,10 @@ impl Emitter for Assembler { Location::GPR(dst) => { dynasm!(self ; adr X(map_gpr(dst).x()), =>label); } - _ => unreachable!() + _ => unreachable!(), } } - + fn emit_cdq(&mut self) { dynasm!( self @@ -397,18 +403,18 @@ impl Emitter for Assembler { Signed => dynasm!(self ; b.vs =>label), // TODO: Review this } } - + fn emit_jmp_location(&mut self, loc: Location) { match loc { Location::GPR(x) => dynasm!(self ; br X(map_gpr(x).x())), Location::Memory(base, disp) => { assert!(disp >= 0); dynasm!(self ; ldr x_tmp1, [ X(map_gpr(base).x()), disp as u32 ]; br x_tmp1); - }, + } _ => unreachable!(), } } - + fn emit_conditional_trap(&mut self, condition: Condition) { use Condition::*; @@ -434,7 +440,7 @@ impl Emitter for Assembler { ; ok: ); } - + fn emit_set(&mut self, condition: Condition, dst: GPR) { use Condition::*; @@ -461,7 +467,7 @@ impl Emitter for Assembler { ; ok: ); } - + fn emit_push(&mut self, sz: Size, src: Location) { match (sz, src) { (Size::S64, Location::Imm32(src)) => dynasm!(self @@ -579,7 +585,7 @@ impl Emitter for Assembler { ; ldr x_tmp1, [X(map_gpr(left).x()), disp as u32] ; cmp X(map_gpr(right).x()), x_tmp1 ), - _ => unreachable!() + _ => unreachable!(), } } fn emit_add(&mut self, sz: Size, src: Location, dst: Location) { @@ -588,7 +594,7 @@ impl Emitter for Assembler { fn emit_sub(&mut self, sz: Size, src: Location, dst: Location) { binop_all_nofp!(sub, self, sz, src, dst, { unreachable!("sub") }); } - + fn emit_imul(&mut self, sz: Size, src: Location, dst: Location) { binop_gpr_gpr!(mul, self, sz, src, dst, { binop_mem_gpr!(mul, self, sz, src, dst, { unreachable!() }) @@ -606,89 +612,299 @@ impl Emitter for Assembler { ); } - fn emit_div(&mut self, sz: Size, divisor: Location) { unimplemented!("instruction") } - fn emit_idiv(&mut self, sz: Size, divisor: Location) { unimplemented!("instruction") } - fn emit_shl(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } - fn emit_shr(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } - fn emit_sar(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } - fn emit_rol(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } - fn emit_ror(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } - fn emit_and(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } - fn emit_or(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } - fn emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } - fn emit_tzcnt(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } - fn emit_popcnt(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } - fn emit_movzx(&mut self, sz_src: Size, src: Location, sz_dst: Size, dst: Location) { unimplemented!("instruction") } - fn emit_movsx(&mut self, sz_src: Size, src: Location, sz_dst: Size, dst: Location) { unimplemented!("instruction") } - - fn emit_btc_gpr_imm8_32(&mut self, src: u8, dst: GPR) { unimplemented!("instruction") } - fn emit_btc_gpr_imm8_64(&mut self, src: u8, dst: GPR) { unimplemented!("instruction") } - - fn emit_cmovae_gpr_32(&mut self, src: GPR, dst: GPR) { unimplemented!("instruction") } - fn emit_cmovae_gpr_64(&mut self, src: GPR, dst: GPR) { unimplemented!("instruction") } - - fn emit_vaddss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vaddsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vsubss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vsubsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vmulss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vmulsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vdivss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vdivsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vmaxss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vmaxsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vminss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vminsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - - fn emit_vcmpeqss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vcmpeqsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - - fn emit_vcmpneqss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vcmpneqsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - - fn emit_vcmpltss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vcmpltsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - - fn emit_vcmpless(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vcmplesd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - - fn emit_vcmpgtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vcmpgtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - - fn emit_vcmpgess(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vcmpgesd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - - fn emit_vsqrtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vsqrtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - - fn emit_vroundss_nearest(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vroundss_floor(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vroundss_ceil(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vroundss_trunc(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vroundsd_nearest(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vroundsd_floor(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vroundsd_ceil(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vroundsd_trunc(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - - fn emit_vcvtss2sd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vcvtsd2ss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - - fn emit_ucomiss(&mut self, src: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_ucomisd(&mut self, src: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } - - fn emit_cvttss2si_32(&mut self, src: XMMOrMemory, dst: GPR) { unimplemented!("instruction") } - fn emit_cvttss2si_64(&mut self, src: XMMOrMemory, dst: GPR) { unimplemented!("instruction") } - fn emit_cvttsd2si_32(&mut self, src: XMMOrMemory, dst: GPR) { unimplemented!("instruction") } - fn emit_cvttsd2si_64(&mut self, src: XMMOrMemory, dst: GPR) { unimplemented!("instruction") } - - fn emit_vcvtsi2ss_32(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vcvtsi2ss_64(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vcvtsi2sd_32(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { unimplemented!("instruction") } - fn emit_vcvtsi2sd_64(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { unimplemented!("instruction") } - - fn emit_test_gpr_64(&mut self, reg: GPR) { unimplemented!("instruction") } - - fn emit_ud2(&mut self) { dynasm!(self ; brk 2) } + fn emit_div(&mut self, sz: Size, divisor: Location) { + unimplemented!("instruction") + } + fn emit_idiv(&mut self, sz: Size, divisor: Location) { + unimplemented!("instruction") + } + fn emit_shl(&mut self, sz: Size, src: Location, dst: Location) { + //binop_all_nofp!(ushl, self, sz, src, dst, { unreachable!("shl") }); + unimplemented!("instruction") + } + fn emit_shr(&mut self, sz: Size, src: Location, dst: Location) { + unimplemented!("instruction") + } + fn emit_sar(&mut self, sz: Size, src: Location, dst: Location) { + unimplemented!("instruction") + } + fn emit_rol(&mut self, sz: Size, src: Location, dst: Location) { + unimplemented!("instruction") + } + fn emit_ror(&mut self, sz: Size, src: Location, dst: Location) { + unimplemented!("instruction") + } + fn emit_and(&mut self, sz: Size, src: Location, dst: Location) { + binop_all_nofp!(and, self, sz, src, dst, { unreachable!("and") }); + } + fn emit_or(&mut self, sz: Size, src: Location, dst: Location) { + //binop_all_nofp!(or, self, sz, src, dst, { unreachable!("or") }); + unimplemented!("instruction"); + } + fn emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location) { + match sz { + Size::S32 => { + match src { + Location::Imm32(x) => dynasm!(self + ; b >after + ; data: + ; .dword x as i32 + ; after: + ; ldr w_tmp2, dynasm!(self + ; clz w_tmp1, W(map_gpr(x).x()) + ), + Location::Memory(base, disp) => { + assert!(disp >= 0); + dynasm!(self + ; ldr w_tmp1, [X(map_gpr(base).x()), disp as u32] + ; clz w_tmp1, w_tmp1 + ); + } + _ => unreachable!(), + } + match dst { + Location::GPR(x) => dynasm!( + self + ; mov W(map_gpr(x).x()), w_tmp1 + ), + Location::Memory(base, disp) => { + assert!(disp >= 0); + dynasm!( + self + ; str w_tmp1, [X(map_gpr(base).x()), disp as u32] + ) + } + _ => unreachable!(), + } + } + Size::S64 => { + match src { + Location::Imm32(x) => dynasm!(self + ; b >after + ; data: + ; .qword x as i64 + ; after: + ; ldr x_tmp2, dynasm!(self + ; clz x_tmp1, X(map_gpr(x).x()) + ), + Location::Memory(base, disp) => { + assert!(disp >= 0); + dynasm!(self + ; ldr x_tmp1, [X(map_gpr(base).x()), disp as u32] + ; clz x_tmp1, x_tmp1 + ); + } + _ => unreachable!(), + } + match dst { + Location::GPR(x) => dynasm!( + self + ; mov X(map_gpr(x).x()), x_tmp1 + ), + Location::Memory(base, disp) => { + assert!(disp >= 0); + dynasm!( + self + ; str x_tmp1, [X(map_gpr(base).x()), disp as u32] + ) + } + _ => unreachable!(), + } + } + _ => unreachable!(), + } + } + fn emit_tzcnt(&mut self, sz: Size, src: Location, dst: Location) { + unimplemented!("instruction") + } + fn emit_popcnt(&mut self, sz: Size, src: Location, dst: Location) { + unimplemented!("instruction") + } + fn emit_movzx(&mut self, sz_src: Size, src: Location, sz_dst: Size, dst: Location) { + unimplemented!("instruction") + } + fn emit_movsx(&mut self, sz_src: Size, src: Location, sz_dst: Size, dst: Location) { + unimplemented!("instruction") + } + + fn emit_btc_gpr_imm8_32(&mut self, src: u8, dst: GPR) { + unimplemented!("instruction") + } + fn emit_btc_gpr_imm8_64(&mut self, src: u8, dst: GPR) { + unimplemented!("instruction") + } + + fn emit_cmovae_gpr_32(&mut self, src: GPR, dst: GPR) { + unimplemented!("instruction") + } + fn emit_cmovae_gpr_64(&mut self, src: GPR, dst: GPR) { + unimplemented!("instruction") + } + + fn emit_vaddss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vaddsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vsubss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vsubsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vmulss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vmulsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vdivss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vdivsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vmaxss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vmaxsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vminss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vminsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + + fn emit_vcmpeqss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vcmpeqsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + + fn emit_vcmpneqss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vcmpneqsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + + fn emit_vcmpltss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vcmpltsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + + fn emit_vcmpless(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vcmplesd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + + fn emit_vcmpgtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vcmpgtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + + fn emit_vcmpgess(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vcmpgesd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + + fn emit_vsqrtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vsqrtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + + fn emit_vroundss_nearest(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vroundss_floor(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vroundss_ceil(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vroundss_trunc(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vroundsd_nearest(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vroundsd_floor(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vroundsd_ceil(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vroundsd_trunc(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + + fn emit_vcvtss2sd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vcvtsd2ss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + + fn emit_ucomiss(&mut self, src: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_ucomisd(&mut self, src: XMMOrMemory, dst: XMM) { + unimplemented!("instruction") + } + + fn emit_cvttss2si_32(&mut self, src: XMMOrMemory, dst: GPR) { + unimplemented!("instruction") + } + fn emit_cvttss2si_64(&mut self, src: XMMOrMemory, dst: GPR) { + unimplemented!("instruction") + } + fn emit_cvttsd2si_32(&mut self, src: XMMOrMemory, dst: GPR) { + unimplemented!("instruction") + } + fn emit_cvttsd2si_64(&mut self, src: XMMOrMemory, dst: GPR) { + unimplemented!("instruction") + } + + fn emit_vcvtsi2ss_32(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vcvtsi2ss_64(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vcvtsi2sd_32(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { + unimplemented!("instruction") + } + fn emit_vcvtsi2sd_64(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { + unimplemented!("instruction") + } + + fn emit_test_gpr_64(&mut self, reg: GPR) { + unimplemented!("instruction") + } + + fn emit_ud2(&mut self) { + dynasm!(self ; brk 2) + } fn emit_ret(&mut self) { dynasm!(self ; ldr x_tmp1, [x_rsp] @@ -745,10 +961,12 @@ impl Emitter for Assembler { ; br x_tmp1 ; done: ); - }, + } _ => unreachable!(), } } - fn emit_bkpt(&mut self) { dynasm!(self ; brk 1) } + fn emit_bkpt(&mut self) { + dynasm!(self ; brk 1) + } } From 9b77677e4b6b9b0281dbcc7dcd9adb1c37ba7716 Mon Sep 17 00:00:00 2001 From: losfair Date: Sun, 15 Sep 2019 18:23:42 +0800 Subject: [PATCH 004/342] Relax constraints a bit to compile on aarch64. --- lib/runtime-core/src/fault.rs | 18 ++- lib/runtime-core/src/lib.rs | 2 +- lib/runtime-core/src/state.rs | 165 +++++++++++----------- lib/singlepass-backend/src/emitter_x64.rs | 9 +- 4 files changed, 110 insertions(+), 84 deletions(-) diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index 2d46d8ca25c..a826e1bbd94 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -1,9 +1,13 @@ pub mod raw { use std::ffi::c_void; + #[cfg(target_arch = "x86_64")] extern "C" { pub fn run_on_alternative_stack(stack_end: *mut u64, stack_begin: *mut u64) -> u64; pub fn register_preservation_trampoline(); // NOT safe to call directly + } + + extern "C" { pub fn setjmp(env: *mut c_void) -> i32; pub fn longjmp(env: *mut c_void, val: i32) -> !; } @@ -25,13 +29,14 @@ use std::process; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Once; +#[cfg(target_arch = "x86_64")] pub(crate) unsafe fn run_on_alternative_stack(stack_end: *mut u64, stack_begin: *mut u64) -> u64 { raw::run_on_alternative_stack(stack_end, stack_begin) } const TRAP_STACK_SIZE: usize = 1048576; // 1MB -const SETJMP_BUFFER_LEN: usize = 27; +const SETJMP_BUFFER_LEN: usize = 128; type SetJmpBuffer = [i32; SETJMP_BUFFER_LEN]; struct UnwindInfo { @@ -181,6 +186,12 @@ unsafe fn with_breakpoint_map) -> R>(f: F) - f(inner.breakpoints.as_ref()) } +#[cfg(not(target_arch = "x86_64"))] +pub fn allocate_and_run R>(size: usize, f: F) -> R { + unimplemented!("allocate_and_run only supported on x86_64"); +} + +#[cfg(target_arch = "x86_64")] pub fn allocate_and_run R>(size: usize, f: F) -> R { struct Context R, R> { f: Option, @@ -353,6 +364,11 @@ pub struct FaultInfo { pub known_registers: [Option; 24], } +#[cfg(target_arch = "aarch64")] +pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> FaultInfo { + unimplemented!("get_fault_info is not yet implemented for aarch64."); +} + #[cfg(all(target_os = "linux", target_arch = "x86_64"))] pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> FaultInfo { use libc::{ diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index fa4450693ee..6d6d1e3bb47 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -53,7 +53,7 @@ pub mod vm; pub mod vmcalls; #[cfg(all(unix, target_arch = "x86_64"))] pub use trampoline_x64 as trampoline; -#[cfg(all(unix, target_arch = "x86_64"))] +#[cfg(unix)] pub mod fault; pub mod state; #[cfg(feature = "managed")] diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index b6bbb95f50d..f61c6aa5c8e 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -398,8 +398,91 @@ impl InstanceImage { } } -#[cfg(all(unix, target_arch = "x86_64"))] +pub mod x64_decl { + use super::*; + #[repr(u8)] + #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] + pub enum GPR { + RAX, + RCX, + RDX, + RBX, + RSP, + RBP, + RSI, + RDI, + R8, + R9, + R10, + R11, + R12, + R13, + R14, + R15, + } + + #[repr(u8)] + #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] + pub enum XMM { + XMM0, + XMM1, + XMM2, + XMM3, + XMM4, + XMM5, + XMM6, + XMM7, + } + + #[derive(Copy, Clone, Debug, Eq, PartialEq)] + pub enum X64Register { + GPR(GPR), + XMM(XMM), + } + + impl X64Register { + pub fn to_index(&self) -> RegisterIndex { + match *self { + X64Register::GPR(x) => RegisterIndex(x as usize), + X64Register::XMM(x) => RegisterIndex(x as usize + 16), + } + } + + pub fn from_dwarf_regnum(x: u16) -> Option { + Some(match x { + 0 => X64Register::GPR(GPR::RAX), + 1 => X64Register::GPR(GPR::RDX), + 2 => X64Register::GPR(GPR::RCX), + 3 => X64Register::GPR(GPR::RBX), + 4 => X64Register::GPR(GPR::RSI), + 5 => X64Register::GPR(GPR::RDI), + 6 => X64Register::GPR(GPR::RBP), + 7 => X64Register::GPR(GPR::RSP), + 8 => X64Register::GPR(GPR::R8), + 9 => X64Register::GPR(GPR::R9), + 10 => X64Register::GPR(GPR::R10), + 11 => X64Register::GPR(GPR::R11), + 12 => X64Register::GPR(GPR::R12), + 13 => X64Register::GPR(GPR::R13), + 14 => X64Register::GPR(GPR::R14), + 15 => X64Register::GPR(GPR::R15), + + 17 => X64Register::XMM(XMM::XMM0), + 18 => X64Register::XMM(XMM::XMM1), + 19 => X64Register::XMM(XMM::XMM2), + 20 => X64Register::XMM(XMM::XMM3), + 21 => X64Register::XMM(XMM::XMM4), + 22 => X64Register::XMM(XMM::XMM5), + 23 => X64Register::XMM(XMM::XMM6), + 24 => X64Register::XMM(XMM::XMM7), + _ => return None, + }) + } + } +} + pub mod x64 { + pub use super::x64_decl::*; use super::*; use crate::codegen::BreakpointMap; use crate::fault::{ @@ -998,84 +1081,4 @@ pub mod x64 { unreachable!(); } - - #[repr(u8)] - #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] - pub enum GPR { - RAX, - RCX, - RDX, - RBX, - RSP, - RBP, - RSI, - RDI, - R8, - R9, - R10, - R11, - R12, - R13, - R14, - R15, - } - - #[repr(u8)] - #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] - pub enum XMM { - XMM0, - XMM1, - XMM2, - XMM3, - XMM4, - XMM5, - XMM6, - XMM7, - } - - #[derive(Copy, Clone, Debug, Eq, PartialEq)] - pub enum X64Register { - GPR(GPR), - XMM(XMM), - } - - impl X64Register { - pub fn to_index(&self) -> RegisterIndex { - match *self { - X64Register::GPR(x) => RegisterIndex(x as usize), - X64Register::XMM(x) => RegisterIndex(x as usize + 16), - } - } - - pub fn from_dwarf_regnum(x: u16) -> Option { - Some(match x { - 0 => X64Register::GPR(GPR::RAX), - 1 => X64Register::GPR(GPR::RDX), - 2 => X64Register::GPR(GPR::RCX), - 3 => X64Register::GPR(GPR::RBX), - 4 => X64Register::GPR(GPR::RSI), - 5 => X64Register::GPR(GPR::RDI), - 6 => X64Register::GPR(GPR::RBP), - 7 => X64Register::GPR(GPR::RSP), - 8 => X64Register::GPR(GPR::R8), - 9 => X64Register::GPR(GPR::R9), - 10 => X64Register::GPR(GPR::R10), - 11 => X64Register::GPR(GPR::R11), - 12 => X64Register::GPR(GPR::R12), - 13 => X64Register::GPR(GPR::R13), - 14 => X64Register::GPR(GPR::R14), - 15 => X64Register::GPR(GPR::R15), - - 17 => X64Register::XMM(XMM::XMM0), - 18 => X64Register::XMM(XMM::XMM1), - 19 => X64Register::XMM(XMM::XMM2), - 20 => X64Register::XMM(XMM::XMM3), - 21 => X64Register::XMM(XMM::XMM4), - 22 => X64Register::XMM(XMM::XMM5), - 23 => X64Register::XMM(XMM::XMM6), - 24 => X64Register::XMM(XMM::XMM7), - _ => return None, - }) - } - } } diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index 24e01231ab5..2bc232a7879 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -1,5 +1,5 @@ use dynasmrt::{x64::Assembler, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi}; -pub use wasmer_runtime_core::state::x64::{GPR, XMM}; +pub use wasmer_runtime_core::state::x64_decl::{GPR, XMM}; #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum Location { @@ -170,6 +170,13 @@ pub trait Emitter { fn emit_bkpt(&mut self); } +fn _dummy(a: &mut Assembler) { + dynasm!( + self + ; .arch x64 + ); +} + macro_rules! unop_gpr { ($ins:ident, $assembler:tt, $sz:expr, $loc:expr, $otherwise:block) => { match ($sz, $loc) { From 2af69f6710784ce0b62ace886dcb721e6554aa77 Mon Sep 17 00:00:00 2001 From: losfair Date: Sun, 15 Sep 2019 18:32:02 +0800 Subject: [PATCH 005/342] Fixed compilation on aarch64. --- lib/runtime-core/src/fault.rs | 10 ++++++++++ lib/runtime-core/src/lib.rs | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index a826e1bbd94..e6fc8e400de 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -7,6 +7,11 @@ pub mod raw { pub fn register_preservation_trampoline(); // NOT safe to call directly } + #[cfg(not(target_arch = "x86_64"))] + pub extern "C" fn register_preservation_trampoline() { + unimplemented!("register_preservation_trampoline"); + } + extern "C" { pub fn setjmp(env: *mut c_void) -> i32; pub fn longjmp(env: *mut c_void, val: i32) -> !; @@ -34,6 +39,11 @@ pub(crate) unsafe fn run_on_alternative_stack(stack_end: *mut u64, stack_begin: raw::run_on_alternative_stack(stack_end, stack_begin) } +#[cfg(not(target_arch = "x86_64"))] +pub(crate) unsafe fn run_on_alternative_stack(stack_end: *mut u64, stack_begin: *mut u64) -> u64 { + unimplemented!("run_on_alternative_stack"); +} + const TRAP_STACK_SIZE: usize = 1048576; // 1MB const SETJMP_BUFFER_LEN: usize = 128; diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index 6d6d1e3bb47..e876ac87c0f 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -1,7 +1,7 @@ #![deny( dead_code, nonstandard_style, - unused_imports, +// unused_imports, unused_mut, unused_variables, unused_unsafe, From 96163a07a6b2b6dd83d35991c3f0497dfa3e5d99 Mon Sep 17 00:00:00 2001 From: losfair Date: Sun, 15 Sep 2019 18:33:53 +0800 Subject: [PATCH 006/342] Temporarily disable all lints in runtime-core. --- lib/runtime-core/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index e876ac87c0f..4c9306e3e07 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -1,12 +1,12 @@ -#![deny( +/*#![deny( dead_code, nonstandard_style, -// unused_imports, + unused_imports, unused_mut, unused_variables, unused_unsafe, unreachable_patterns -)] +)]*/ #![cfg_attr(nightly, feature(unwind_attributes))] #![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")] #![doc(html_logo_url = "https://avatars3.githubusercontent.com/u/44205449?s=200&v=4")] From 05557fc9ad6abce318bf7605c4169e77656b6992 Mon Sep 17 00:00:00 2001 From: losfair Date: Mon, 16 Sep 2019 23:46:10 +0800 Subject: [PATCH 007/342] Bump dynasm to v0.5.1 --- lib/singlepass-backend/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/singlepass-backend/Cargo.toml b/lib/singlepass-backend/Cargo.toml index 87eb6e6e4eb..7a750000743 100644 --- a/lib/singlepass-backend/Cargo.toml +++ b/lib/singlepass-backend/Cargo.toml @@ -11,8 +11,8 @@ readme = "README.md" [dependencies] wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" } wasmparser = "0.35.1" -dynasm = "0.5.0" -dynasmrt = "0.5.0" +dynasm = "0.5.1" +dynasmrt = "0.5.1" lazy_static = "1.3.0" byteorder = "1.3.2" nix = "0.15.0" From d8b313e3fdd355071dbe2c33c7dc55010d2995ef Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 17 Sep 2019 00:49:21 +0800 Subject: [PATCH 008/342] Fix emit_lea. --- lib/singlepass-backend/src/translator_aarch64.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 6d7d699e18f..86512974192 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -325,10 +325,18 @@ impl Emitter for Assembler { fn emit_lea(&mut self, sz: Size, src: Location, dst: Location) { match (sz, src, dst) { (Size::S32, Location::Memory(src, disp), Location::GPR(dst)) => { - dynasm!(self ; add W(map_gpr(dst).x()), W(map_gpr(src).x()), disp as u32); + if disp >= 0 { + dynasm!(self ; add W(map_gpr(dst).x()), W(map_gpr(src).x()), disp as u32); + } else { + dynasm!(self ; sub W(map_gpr(dst).x()), W(map_gpr(src).x()), (-disp) as u32); + } } (Size::S64, Location::Memory(src, disp), Location::GPR(dst)) => { - dynasm!(self ; add X(map_gpr(dst).x()), X(map_gpr(src).x()), disp as u32); + if disp >= 0 { + dynasm!(self ; add X(map_gpr(dst).x()), X(map_gpr(src).x()), disp as u32); + } else { + dynasm!(self ; sub X(map_gpr(dst).x()), X(map_gpr(src).x()), (-disp) as u32); + } } _ => unreachable!(), } From 574e4c477ffa543a637d11d1de8996ce61f2d322 Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 17 Sep 2019 00:54:34 +0800 Subject: [PATCH 009/342] Print return value from pure WASM binary. --- src/bin/wasmer.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 651981b3bbe..3bd4aa21cd8 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -661,11 +661,12 @@ fn execute_wasm(options: &Run) -> Result<(), String> { .map(|arg| arg.as_str()) .map(|x| Value::I32(x.parse().unwrap())) .collect(); - instance + let result = instance .dyn_func("main") .map_err(|e| format!("{:?}", e))? .call(&args) .map_err(|e| format!("{:?}", e))?; + println!("main() returned: {:?}", result); } } From b57aba4ae7b480566e11ad91bff73b4d320593ac Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 18 Sep 2019 02:14:13 +0800 Subject: [PATCH 010/342] Add homomorphic host redirection abstraction for vm->host calls. --- Cargo.lock | 12 +++---- lib/singlepass-backend/src/codegen_x64.rs | 2 +- lib/singlepass-backend/src/emitter_x64.rs | 6 ++++ .../src/translator_aarch64.rs | 36 +++++++++++++++++++ 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f0f7b3014ff..5f15df164e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -428,7 +428,7 @@ dependencies = [ [[package]] name = "dynasm" -version = "0.5.0" +version = "0.5.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)", @@ -442,7 +442,7 @@ dependencies = [ [[package]] name = "dynasmrt" -version = "0.5.0" +version = "0.5.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)", @@ -1692,8 +1692,8 @@ version = "0.6.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dynasm 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dynasmrt 0.5.0 (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.62 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1875,8 +1875,8 @@ dependencies = [ "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 digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -"checksum dynasm 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56607fba702a46df49ce4f6e1e7b7cc55df2c8c5066630a1b4e91939f8948795" -"checksum dynasmrt 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81c856c0e3505b907e0f07a70712daf717a204e8195e3f41d20badea3718762c" +"checksum dynasm 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8654f63488a94cd11feac2a609fdcdecd09e02fb582731f635783689fbb429f3" +"checksum dynasmrt 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b0046b083139885c38990f2fb9822d06f6c5902068d93a6ed9e56b63011b9932" "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" diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 708339e6a81..224ca4b4772 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -644,7 +644,7 @@ impl ModuleCodeGenerator ), Location::GPR(GPR::RAX), ); - a.emit_jmp_location(Location::GPR(GPR::RAX)); + a.emit_homomorphic_host_redirection(GPR::RAX); self.func_import_count += 1; diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index 2bc232a7879..4522f089814 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -168,6 +168,8 @@ pub trait Emitter { fn emit_call_location(&mut self, loc: Location); fn emit_bkpt(&mut self); + + fn emit_homomorphic_host_redirection(&mut self, target: GPR); } fn _dummy(a: &mut Assembler) { @@ -940,4 +942,8 @@ impl Emitter for Assembler { fn emit_bkpt(&mut self) { dynasm!(self ; int 0x3); } + + fn emit_homomorphic_host_redirection(&mut self, target: GPR) { + self.emit_jmp_location(Location::GPR(target)); + } } diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 86512974192..8f3f0b0b59d 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -977,4 +977,40 @@ impl Emitter for Assembler { fn emit_bkpt(&mut self) { dynasm!(self ; brk 1) } + + fn emit_homomorphic_host_redirection(&mut self, target: GPR) { + let target = map_gpr(target); + dynasm!( + self + ; sub sp, sp, 16 + ; str x30, [sp, 0] // LR + ; str X(target.x()), [sp, 8] + ; adr x30, >after + + // Put parameters in correct order + ; sub sp, sp, 64 + ; str X(map_gpr(GPR::RDI).x()), [sp, 0] + ; str X(map_gpr(GPR::RSI).x()), [sp, 8] + ; str X(map_gpr(GPR::RDX).x()), [sp, 16] + ; str X(map_gpr(GPR::RCX).x()), [sp, 24] + ; str X(map_gpr(GPR::R8).x()), [sp, 32] + ; str X(map_gpr(GPR::R9).x()), [sp, 40] + ; ldr x0, [sp, 0] + ; ldr x1, [sp, 8] + ; ldr x2, [sp, 16] + ; ldr x3, [sp, 24] + ; ldr x4, [sp, 32] + ; ldr x5, [sp, 40] + ; add sp, sp, 64 + + // Branch to saved target + ; ldr x8, [sp, 8] + ; br x8 + + ; after: + ; ldr x30, [sp, 0] // LR + ; add sp, sp, 16 + ; br x30 + ); + } } From 97b75d01244a013c452997b4ea4d3b57c97a269a Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 18 Sep 2019 02:21:35 +0800 Subject: [PATCH 011/342] Ensure callee-saved registers are properly preserved. --- .../src/translator_aarch64.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 8f3f0b0b59d..6288ae775fb 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -982,9 +982,17 @@ impl Emitter for Assembler { let target = map_gpr(target); dynasm!( self - ; sub sp, sp, 16 + ; sub sp, sp, 80 ; str x30, [sp, 0] // LR ; str X(target.x()), [sp, 8] + // Save callee-saved registers as required by x86-64 conventions. + ; str X(map_gpr(GPR::RBX).x()), [sp, 16] + ; str X(map_gpr(GPR::R12).x()), [sp, 24] + ; str X(map_gpr(GPR::R13).x()), [sp, 32] + ; str X(map_gpr(GPR::R14).x()), [sp, 40] + ; str X(map_gpr(GPR::R15).x()), [sp, 48] + ; str X(map_gpr(GPR::RBP).x()), [sp, 56] + ; str X(map_gpr(GPR::RSP).x()), [sp, 64] ; adr x30, >after // Put parameters in correct order @@ -1009,7 +1017,14 @@ impl Emitter for Assembler { ; after: ; ldr x30, [sp, 0] // LR - ; add sp, sp, 16 + ; ldr X(map_gpr(GPR::RBX).x()), [sp, 16] + ; ldr X(map_gpr(GPR::R12).x()), [sp, 24] + ; ldr X(map_gpr(GPR::R13).x()), [sp, 32] + ; ldr X(map_gpr(GPR::R14).x()), [sp, 40] + ; ldr X(map_gpr(GPR::R15).x()), [sp, 48] + ; ldr X(map_gpr(GPR::RBP).x()), [sp, 56] + ; ldr X(map_gpr(GPR::RSP).x()), [sp, 64] + ; add sp, sp, 80 ; br x30 ); } From e40600533ed419898961ad6e62f26364162a4b4e Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 18 Sep 2019 02:30:45 +0800 Subject: [PATCH 012/342] Add missing `emit_mov` variants. --- lib/singlepass-backend/src/translator_aarch64.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 6288ae775fb..0b7064cf2eb 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -301,6 +301,10 @@ impl Emitter for Assembler { assert!(disp >= 0); dynasm!(self ; str W(map_gpr(src).x()), [ X(map_gpr(dst).x()), disp as u32 ] ); } + (Size::S32, Location::Imm32(x), Location::Memory(dst, disp)) => { + assert!(disp >= 0); + dynasm!(self ; b >after; data: ; .dword x as i32; after: ; ldr w_tmp1, { dynasm!(self ; b >after; data: ; .dword x as i32; after: ; ldr W(map_gpr(dst).x()), = 0); dynasm!(self ; str X(map_gpr(src).x()), [ X(map_gpr(dst).x()), disp as u32 ] ); } + (Size::S64, Location::Imm32(x), Location::Memory(dst, disp)) => { + assert!(disp >= 0); + dynasm!(self ; b >after; data: ; .qword x as i64; after: ; ldr x_tmp1, { dynasm!(self ; b >after; data: ; .qword x as i64; after: ; ldr X(map_gpr(dst).x()), Date: Wed, 18 Sep 2019 02:38:35 +0800 Subject: [PATCH 013/342] Fix memory grow --- lib/singlepass-backend/src/codegen_x64.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 224ca4b4772..260a0f66709 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -4167,7 +4167,13 @@ impl FunctionCodeGenerator for X64FunctionCode { a, &mut self.machine, |a| { - a.emit_call_location(Location::GPR(GPR::RAX)); + let label = a.get_label(); + let after = a.get_label(); + a.emit_jmp(Condition::None, after); + a.emit_label(label); + a.emit_homomorphic_host_redirection(GPR::RAX); + a.emit_label(after); + a.emit_call_label(label); }, ::std::iter::once(Location::Imm32(memory_index.index() as u32)) .chain(::std::iter::once(param_pages)), From 8a91f801b9db58011eca57762d1b6f5d38f816fc Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 18 Sep 2019 21:47:31 +0800 Subject: [PATCH 014/342] Fix return from homomorphic host redirection trampoline. --- lib/singlepass-backend/src/translator_aarch64.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 0b7064cf2eb..e1bb44adc48 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -1033,7 +1033,10 @@ impl Emitter for Assembler { ; ldr X(map_gpr(GPR::RBP).x()), [sp, 56] ; ldr X(map_gpr(GPR::RSP).x()), [sp, 64] ; add sp, sp, 80 - ; br x30 + + ; ldr x_tmp1, [x_rsp] + ; add x_rsp, x_rsp, 8 + ; br x_tmp1 ); } } From 5f8b289751fb9b025c1384d78dc53ba5127942bf Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 19 Sep 2019 01:04:20 +0800 Subject: [PATCH 015/342] movzx/movsx --- .../src/translator_aarch64.rs | 61 +++++++++++++++++-- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index e1bb44adc48..9d0bee823d3 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -654,8 +654,7 @@ impl Emitter for Assembler { binop_all_nofp!(and, self, sz, src, dst, { unreachable!("and") }); } fn emit_or(&mut self, sz: Size, src: Location, dst: Location) { - //binop_all_nofp!(or, self, sz, src, dst, { unreachable!("or") }); - unimplemented!("instruction"); + binop_all_nofp!(orr, self, sz, src, dst, { unreachable!("or") }); } fn emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location) { match sz { @@ -742,10 +741,64 @@ impl Emitter for Assembler { fn emit_popcnt(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } - fn emit_movzx(&mut self, sz_src: Size, src: Location, sz_dst: Size, dst: Location) { - unimplemented!("instruction") + fn emit_movzx(&mut self, sz_src: Size, src: Location, _sz_dst: Size, dst: Location) { + match (sz_src, src, dst) { + (Size::S8, Location::GPR(src), Location::GPR(dst)) => { + dynasm!(self ; uxtb W(map_gpr(dst).x()), W(map_gpr(src).x())); + } + (Size::S16, Location::GPR(src), Location::GPR(dst)) => { + dynasm!(self ; uxth W(map_gpr(dst).x()), W(map_gpr(src).x())); + } + (Size::S8, Location::Memory(src, disp), Location::GPR(dst)) => { + assert!(disp >= 0); + dynasm!(self ; ldrb W(map_gpr(dst).x()), [X(map_gpr(src).x()), disp as u32]); + } + (Size::S16, Location::Memory(src, disp), Location::GPR(dst)) => { + assert!(disp >= 0); + dynasm!(self ; ldrh W(map_gpr(dst).x()), [X(map_gpr(src).x()), disp as u32]); + } + _ => unreachable!(), + } } fn emit_movsx(&mut self, sz_src: Size, src: Location, sz_dst: Size, dst: Location) { + match (sz_src, src, sz_dst, dst) { + (Size::S8, Location::GPR(src), Size::S32, Location::GPR(dst)) => { + dynasm!(self ; sxtb W(map_gpr(dst).x()), W(map_gpr(src).x())); + } + (Size::S16, Location::GPR(src), Size::S32, Location::GPR(dst)) => { + dynasm!(self ; sxth W(map_gpr(dst).x()), W(map_gpr(src).x())); + } + (Size::S8, Location::Memory(src, disp), Size::S32, Location::GPR(dst)) => { + assert!(disp >= 0); + dynasm!(self ; ldrb W(map_gpr(dst).x()), [X(map_gpr(src).x()), disp as u32]; sxtb W(map_gpr(dst).x()), W(map_gpr(dst).x())); + } + (Size::S16, Location::Memory(src, disp), Size::S32, Location::GPR(dst)) => { + assert!(disp >= 0); + dynasm!(self ; ldrh W(map_gpr(dst).x()), [X(map_gpr(src).x()), disp as u32]; sxth W(map_gpr(dst).x()), W(map_gpr(dst).x())); + } + (Size::S8, Location::GPR(src), Size::S64, Location::GPR(dst)) => { + dynasm!(self ; sxtb X(map_gpr(dst).x()), W(map_gpr(src).x())); + } + (Size::S16, Location::GPR(src), Size::S64, Location::GPR(dst)) => { + dynasm!(self ; sxth X(map_gpr(dst).x()), W(map_gpr(src).x())); + } + (Size::S32, Location::GPR(src), Size::S64, Location::GPR(dst)) => { + dynasm!(self ; sxtw X(map_gpr(dst).x()), W(map_gpr(src).x())); + } + (Size::S8, Location::Memory(src, disp), Size::S64, Location::GPR(dst)) => { + assert!(disp >= 0); + dynasm!(self ; ldrb W(map_gpr(dst).x()), [X(map_gpr(src).x()), disp as u32]; sxtb X(map_gpr(dst).x()), W(map_gpr(dst).x())); + } + (Size::S16, Location::Memory(src, disp), Size::S64, Location::GPR(dst)) => { + assert!(disp >= 0); + dynasm!(self ; ldrh W(map_gpr(dst).x()), [X(map_gpr(src).x()), disp as u32]; sxth X(map_gpr(dst).x()), W(map_gpr(dst).x())); + } + (Size::S32, Location::Memory(src, disp), Size::S64, Location::GPR(dst)) => { + assert!(disp >= 0); + dynasm!(self ; ldrh W(map_gpr(dst).x()), [X(map_gpr(src).x()), disp as u32]; sxtw X(map_gpr(dst).x()), W(map_gpr(dst).x())); + } + _ => unreachable!(), + } unimplemented!("instruction") } From a124d87d0f5100346ba72b979e963dd876a90f73 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 19 Sep 2019 01:10:23 +0800 Subject: [PATCH 016/342] Fix Operator::MemorySize. --- lib/singlepass-backend/src/codegen_x64.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 260a0f66709..04a4613dc8d 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -4128,7 +4128,13 @@ impl FunctionCodeGenerator for X64FunctionCode { a, &mut self.machine, |a| { - a.emit_call_location(Location::GPR(GPR::RAX)); + let label = a.get_label(); + let after = a.get_label(); + a.emit_jmp(Condition::None, after); + a.emit_label(label); + a.emit_homomorphic_host_redirection(GPR::RAX); + a.emit_label(after); + a.emit_call_label(label); }, ::std::iter::once(Location::Imm32(memory_index.index() as u32)), None, From 3dadbc15c923f2625e35fce92f6e2d0eb43ed1b4 Mon Sep 17 00:00:00 2001 From: losfair Date: Mon, 23 Sep 2019 22:30:08 +0800 Subject: [PATCH 017/342] Integer subset done. --- .../src/translator_aarch64.rs | 323 ++++++++++++++---- 1 file changed, 250 insertions(+), 73 deletions(-) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 9d0bee823d3..63f8132c7bb 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -264,6 +264,62 @@ macro_rules! binop_all_nofp { }; } +macro_rules! binop_shift { + ($ins:ident, $assembler:tt, $sz:expr, $src:expr, $dst:expr, $otherwise:block) => { + match ($sz, $src, $dst) { + (Size::S32, Location::Imm8(imm), Location::GPR(dst)) => { + assert!(imm < 32); + dynasm!($assembler ; $ins W(map_gpr(dst).x()), W(map_gpr(dst).x()), imm as u32); + }, + (Size::S32, Location::Imm8(imm), Location::Memory(base, disp)) => { + assert!(imm < 32); + assert!(disp >= 0); + dynasm!($assembler + ; ldr w_tmp1, [X(map_gpr(base).x()), disp as u32] + ; $ins w_tmp1, w_tmp1, imm as u32 + ; str w_tmp1, [X(map_gpr(base).x()), disp as u32] + ); + }, + (Size::S32, Location::GPR(GPR::RCX), Location::GPR(dst)) => { + dynasm!($assembler ; $ins W(map_gpr(dst).x()), W(map_gpr(dst).x()), W(map_gpr(GPR::RCX).x())); + }, + (Size::S32, Location::GPR(GPR::RCX), Location::Memory(base, disp)) => { + assert!(disp >= 0); + dynasm!($assembler + ; ldr w_tmp1, [X(map_gpr(base).x()), disp as u32] + ; $ins w_tmp1, w_tmp1, W(map_gpr(GPR::RCX).x()) + ; str w_tmp1, [X(map_gpr(base).x()), disp as u32] + ); + }, + (Size::S64, Location::Imm8(imm), Location::GPR(dst)) => { + assert!(imm < 32); + dynasm!($assembler ; $ins X(map_gpr(dst).x()), X(map_gpr(dst).x()), imm as u32); + }, + (Size::S64, Location::Imm8(imm), Location::Memory(base, disp)) => { + assert!(imm < 32); + assert!(disp >= 0); + dynasm!($assembler + ; ldr x_tmp1, [X(map_gpr(base).x()), disp as u32] + ; $ins x_tmp1, x_tmp1, imm as u32 + ; str x_tmp1, [X(map_gpr(base).x()), disp as u32] + ); + }, + (Size::S64, Location::GPR(GPR::RCX), Location::GPR(dst)) => { + dynasm!($assembler ; $ins X(map_gpr(dst).x()), X(map_gpr(dst).x()), X(map_gpr(GPR::RCX).x())); + }, + (Size::S64, Location::GPR(GPR::RCX), Location::Memory(base, disp)) => { + assert!(disp >= 0); + dynasm!($assembler + ; ldr x_tmp1, [X(map_gpr(base).x()), disp as u32] + ; $ins x_tmp1, x_tmp1, X(map_gpr(GPR::RCX).x()) + ; str x_tmp1, [X(map_gpr(base).x()), disp as u32] + ); + }, + _ => $otherwise + } + } +} + impl Emitter for Assembler { type Label = DynamicLabel; type Offset = AssemblyOffset; @@ -629,117 +685,173 @@ impl Emitter for Assembler { } fn emit_div(&mut self, sz: Size, divisor: Location) { - unimplemented!("instruction") - } - fn emit_idiv(&mut self, sz: Size, divisor: Location) { - unimplemented!("instruction") - } - fn emit_shl(&mut self, sz: Size, src: Location, dst: Location) { - //binop_all_nofp!(ushl, self, sz, src, dst, { unreachable!("shl") }); - unimplemented!("instruction") - } - fn emit_shr(&mut self, sz: Size, src: Location, dst: Location) { - unimplemented!("instruction") - } - fn emit_sar(&mut self, sz: Size, src: Location, dst: Location) { - unimplemented!("instruction") - } - fn emit_rol(&mut self, sz: Size, src: Location, dst: Location) { - unimplemented!("instruction") - } - fn emit_ror(&mut self, sz: Size, src: Location, dst: Location) { - unimplemented!("instruction") - } - fn emit_and(&mut self, sz: Size, src: Location, dst: Location) { - binop_all_nofp!(and, self, sz, src, dst, { unreachable!("and") }); - } - fn emit_or(&mut self, sz: Size, src: Location, dst: Location) { - binop_all_nofp!(orr, self, sz, src, dst, { unreachable!("or") }); - } - fn emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location) { match sz { Size::S32 => { - match src { - Location::Imm32(x) => dynasm!(self - ; b >after - ; data: - ; .dword x as i32 - ; after: - ; ldr w_tmp2, dynasm!(self - ; clz w_tmp1, W(map_gpr(x).x()) + match divisor { + Location::GPR(x) => dynasm!( + self + ; mov w_tmp1, W(map_gpr(x).x()) ), Location::Memory(base, disp) => { assert!(disp >= 0); - dynasm!(self + dynasm!( + self ; ldr w_tmp1, [X(map_gpr(base).x()), disp as u32] - ; clz w_tmp1, w_tmp1 - ); + ) } - _ => unreachable!(), + _ => unreachable!() } - match dst { + dynasm!( + self + ; mov w_tmp2, W(map_gpr(GPR::RAX).x()) + ; udiv W(map_gpr(GPR::RAX).x()), w_tmp2, w_tmp1 + ; msub W(map_gpr(GPR::RDX).x()), W(map_gpr(GPR::RAX).x()), w_tmp1, w_tmp2 + ) + } + Size::S64 => { + match divisor { Location::GPR(x) => dynasm!( self - ; mov W(map_gpr(x).x()), w_tmp1 + ; mov x_tmp1, X(map_gpr(x).x()) ), Location::Memory(base, disp) => { assert!(disp >= 0); dynasm!( self - ; str w_tmp1, [X(map_gpr(base).x()), disp as u32] + ; ldr x_tmp1, [X(map_gpr(base).x()), disp as u32] ) } - _ => unreachable!(), + _ => unreachable!() } + dynasm!( + self + ; mov x_tmp2, X(map_gpr(GPR::RAX).x()) + ; udiv X(map_gpr(GPR::RAX).x()), x_tmp2, x_tmp1 + ; msub X(map_gpr(GPR::RDX).x()), X(map_gpr(GPR::RAX).x()), x_tmp1, x_tmp2 + ) } - Size::S64 => { - match src { - Location::Imm32(x) => dynasm!(self - ; b >after - ; data: - ; .qword x as i64 - ; after: - ; ldr x_tmp2, dynasm!(self - ; clz x_tmp1, X(map_gpr(x).x()) + _ => unreachable!() + } + } + fn emit_idiv(&mut self, sz: Size, divisor: Location) { + match sz { + Size::S32 => { + match divisor { + Location::GPR(x) => dynasm!( + self + ; mov w_tmp1, W(map_gpr(x).x()) ), Location::Memory(base, disp) => { assert!(disp >= 0); - dynasm!(self - ; ldr x_tmp1, [X(map_gpr(base).x()), disp as u32] - ; clz x_tmp1, x_tmp1 - ); + dynasm!( + self + ; ldr w_tmp1, [X(map_gpr(base).x()), disp as u32] + ) } - _ => unreachable!(), + _ => unreachable!() } - match dst { + dynasm!( + self + ; mov w_tmp2, W(map_gpr(GPR::RAX).x()) + ; sdiv W(map_gpr(GPR::RAX).x()), w_tmp2, w_tmp1 + ; msub W(map_gpr(GPR::RDX).x()), W(map_gpr(GPR::RAX).x()), w_tmp1, w_tmp2 + ) + } + Size::S64 => { + match divisor { Location::GPR(x) => dynasm!( self - ; mov X(map_gpr(x).x()), x_tmp1 + ; mov x_tmp1, X(map_gpr(x).x()) ), Location::Memory(base, disp) => { assert!(disp >= 0); dynasm!( self - ; str x_tmp1, [X(map_gpr(base).x()), disp as u32] + ; ldr x_tmp1, [X(map_gpr(base).x()), disp as u32] ) } - _ => unreachable!(), + _ => unreachable!() } + dynasm!( + self + ; mov x_tmp2, X(map_gpr(GPR::RAX).x()) + ; sdiv X(map_gpr(GPR::RAX).x()), x_tmp2, x_tmp1 + ; msub X(map_gpr(GPR::RDX).x()), X(map_gpr(GPR::RAX).x()), x_tmp1, x_tmp2 + ) } - _ => unreachable!(), + _ => unreachable!() } } + fn emit_shl(&mut self, sz: Size, src: Location, dst: Location) { + binop_shift!(lsl, self, sz, src, dst, { unreachable!("shl") }); + } + fn emit_shr(&mut self, sz: Size, src: Location, dst: Location) { + binop_shift!(lsr, self, sz, src, dst, { unreachable!("shr") }); + } + fn emit_sar(&mut self, sz: Size, src: Location, dst: Location) { + binop_shift!(asr, self, sz, src, dst, { unreachable!("sar") }); + } + fn emit_rol(&mut self, sz: Size, src: Location, dst: Location) { + // TODO: We are changing content of `src` (possibly RCX) here. Will this break any assumptions? + match sz { + Size::S32 => { + match src { + Location::Imm8(x) => { + assert!(x < 32); + binop_shift!(ror, self, sz, Location::Imm8(32 - x), dst, { unreachable!("rol") }); + } + Location::GPR(GPR::RCX) => { + dynasm!( + self + ; mov w_tmp1, 32 + ; sub W(map_gpr(GPR::RCX).x()), w_tmp1, W(map_gpr(GPR::RCX).x()) + ); + binop_shift!(ror, self, sz, src, dst, { unreachable!("rol") }); + } + _ => unreachable!() + } + } + Size::S64 => { + match src { + Location::Imm8(x) => { + assert!(x < 64); + binop_shift!(ror, self, sz, Location::Imm8(64 - x), dst, { unreachable!("rol") }); + } + Location::GPR(GPR::RCX) => { + dynasm!( + self + ; mov x_tmp1, 64 + ; sub X(map_gpr(GPR::RCX).x()), x_tmp1, X(map_gpr(GPR::RCX).x()) + ); + binop_shift!(ror, self, sz, src, dst, { unreachable!("rol") }); + } + _ => unreachable!() + } + } + _ => unreachable!() + } + + } + fn emit_ror(&mut self, sz: Size, src: Location, dst: Location) { + binop_shift!(ror, self, sz, src, dst, { unreachable!("ror") }); + } + fn emit_and(&mut self, sz: Size, src: Location, dst: Location) { + binop_all_nofp!(and, self, sz, src, dst, { unreachable!("and") }); + } + fn emit_or(&mut self, sz: Size, src: Location, dst: Location) { + binop_all_nofp!(orr, self, sz, src, dst, { unreachable!("or") }); + } + fn emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location) { + emit_clz_variant(self, sz, &src, &dst, false); + } fn emit_tzcnt(&mut self, sz: Size, src: Location, dst: Location) { - unimplemented!("instruction") + emit_clz_variant(self, sz, &src, &dst, true); } fn emit_popcnt(&mut self, sz: Size, src: Location, dst: Location) { - unimplemented!("instruction") + dynasm!( + self + ; brk 90 // TODO: Implement + ); } fn emit_movzx(&mut self, sz_src: Size, src: Location, _sz_dst: Size, dst: Location) { match (sz_src, src, dst) { @@ -799,16 +911,15 @@ impl Emitter for Assembler { } _ => unreachable!(), } - unimplemented!("instruction") } + // TODO: These instructions are only used in FP opcodes. Implement later. fn emit_btc_gpr_imm8_32(&mut self, src: u8, dst: GPR) { unimplemented!("instruction") } fn emit_btc_gpr_imm8_64(&mut self, src: u8, dst: GPR) { unimplemented!("instruction") } - fn emit_cmovae_gpr_32(&mut self, src: GPR, dst: GPR) { unimplemented!("instruction") } @@ -1093,3 +1204,69 @@ impl Emitter for Assembler { ); } } + +fn emit_clz_variant(assembler: &mut Assembler, sz: Size, src: &Location, dst: &Location, reversed: bool) { + match sz { + Size::S32 => { + match *src { + Location::GPR(src) => { + dynasm!( + assembler + ; mov w_tmp1, W(map_gpr(src).x()) + ) + } + Location::Memory(base, disp) => { + assert!(disp >= 0); + dynasm!( + assembler + ; ldr w_tmp1, [X(map_gpr(base).x()), disp as u32] + ) + } + _ => unreachable!() + } + match *dst { + Location::GPR(dst) => { + if reversed { + dynasm!(assembler ; rbit w_tmp1, w_tmp1); + } + dynasm!( + assembler + ; clz W(map_gpr(dst).x()), w_tmp1 + ); + } + _ => unreachable!() + } + } + Size::S64 => { + match *src { + Location::GPR(src) => { + dynasm!( + assembler + ; mov x_tmp1, X(map_gpr(src).x()) + ) + } + Location::Memory(base, disp) => { + assert!(disp >= 0); + dynasm!( + assembler + ; ldr x_tmp1, [X(map_gpr(base).x()), disp as u32] + ) + } + _ => unreachable!() + } + match *dst { + Location::GPR(dst) => { + if reversed { + dynasm!(assembler ; rbit x_tmp1, x_tmp1) + } + dynasm!( + assembler + ; clz X(map_gpr(dst).x()), x_tmp1 + ); + } + _ => unreachable!() + } + } + _ => unreachable!() + } +} \ No newline at end of file From 89d8b5a41c7af0681efbce835a335bbd40b015e2 Mon Sep 17 00:00:00 2001 From: losfair Date: Sat, 28 Sep 2019 17:31:10 +0800 Subject: [PATCH 018/342] Fixes for aarch64. --- lib/singlepass-backend/src/codegen_x64.rs | 4 +- lib/singlepass-backend/src/emitter_x64.rs | 5 + .../src/translator_aarch64.rs | 571 +++++++++++++----- 3 files changed, 412 insertions(+), 168 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 04a4613dc8d..1b081717a2a 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -4953,7 +4953,9 @@ impl FunctionCodeGenerator for X64FunctionCode { a.emit_lea_label(table_label, Location::GPR(GPR::RCX)); a.emit_mov(Size::S32, cond, Location::GPR(GPR::RDX)); - a.emit_imul_imm32_gpr64(5, GPR::RDX); + + let instr_size = a.get_jmp_instr_size(); + a.emit_imul_imm32_gpr64(instr_size as _, GPR::RDX); a.emit_add(Size::S64, Location::GPR(GPR::RCX), Location::GPR(GPR::RDX)); a.emit_jmp_location(Location::GPR(GPR::RDX)); diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index 4522f089814..41134473a76 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -56,6 +56,7 @@ pub trait Emitter { fn get_label(&mut self) -> Self::Label; fn get_offset(&self) -> Self::Offset; + fn get_jmp_instr_size(&self) -> u8; fn emit_u64(&mut self, x: u64); @@ -471,6 +472,10 @@ impl Emitter for Assembler { self.offset() } + fn get_jmp_instr_size(&self) -> u8 { + 5 + } + fn emit_u64(&mut self, x: u64) { self.push_u64(x); } diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 63f8132c7bb..c01384553e2 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -106,6 +106,8 @@ pub fn get_aarch64_assembler() -> Assembler { ; .alias w_tmp1, w27 ; .alias x_tmp2, x26 ; .alias w_tmp2, w26 + ; .alias x_tmp3, x25 + ; .alias w_tmp3, w25 ); a } @@ -142,29 +144,37 @@ macro_rules! binop_imm32_mem { ($ins:ident, $assembler:tt, $sz:expr, $src:expr, $dst:expr, $otherwise:block) => { match ($sz, $src, $dst) { (Size::S32, Location::Imm32(src), Location::Memory(dst, disp)) => { - assert!(disp >= 0); + if disp >= 0 { + dynasm!($assembler ; add x_tmp3, X(map_gpr(dst).x()), disp as u32); + } else { + dynasm!($assembler ; sub x_tmp3, X(map_gpr(dst).x()), (-disp) as u32); + } dynasm!($assembler ; b >after ; data: ; .dword src as i32 ; after: ; ldr w_tmp1, { - assert!(disp >= 0); + if disp >= 0 { + dynasm!($assembler ; add x_tmp3, X(map_gpr(dst).x()), disp as u32); + } else { + dynasm!($assembler ; sub x_tmp3, X(map_gpr(dst).x()), (-disp) as u32); + } dynasm!($assembler ; b >after ; data: ; .qword src as i64 ; after: ; ldr x_tmp1, $otherwise @@ -211,18 +221,28 @@ macro_rules! binop_gpr_gpr { macro_rules! binop_gpr_mem { ($ins:ident, $assembler:tt, $sz:expr, $src:expr, $dst:expr, $otherwise:block) => { match ($sz, $src, $dst) { - (Size::S32, Location::GPR(src), Location::Memory(dst, disp)) => { + (Size::S32, Location::GPR(src), Location::Memory(base, disp)) => { + if disp >= 0 { + dynasm!($assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!($assembler ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } dynasm!($assembler - ; ldr w_tmp1, [X(map_gpr(dst).x()), disp as u32] + ; ldr w_tmp1, [x_tmp3] ; $ins w_tmp1, w_tmp1, W(map_gpr(src).x()) - ; str w_tmp1, [X(map_gpr(dst).x()), disp as u32] + ; str w_tmp1, [x_tmp3] ); }, - (Size::S64, Location::GPR(src), Location::Memory(dst, disp)) => { + (Size::S64, Location::GPR(src), Location::Memory(base, disp)) => { + if disp >= 0 { + dynasm!($assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!($assembler ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } dynasm!($assembler - ; ldr x_tmp1, [X(map_gpr(dst).x()), disp as u32] + ; ldr x_tmp1, [x_tmp3] ; $ins x_tmp1, x_tmp1, X(map_gpr(src).x()) - ; str x_tmp1, [X(map_gpr(dst).x()), disp as u32] + ; str x_tmp1, [x_tmp3] ); }, _ => $otherwise @@ -233,15 +253,25 @@ macro_rules! binop_gpr_mem { macro_rules! binop_mem_gpr { ($ins:ident, $assembler:tt, $sz:expr, $src:expr, $dst:expr, $otherwise:block) => { match ($sz, $src, $dst) { - (Size::S32, Location::Memory(src, disp), Location::GPR(dst)) => { + (Size::S32, Location::Memory(base, disp), Location::GPR(dst)) => { + if disp >= 0 { + dynasm!($assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!($assembler ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } dynasm!($assembler - ; ldr w_tmp1, [X(map_gpr(src).x()), disp as u32] + ; ldr w_tmp1, [x_tmp3] ; $ins W(map_gpr(dst).x()), W(map_gpr(dst).x()), w_tmp1 ) }, - (Size::S64, Location::Memory(src, disp), Location::GPR(dst)) => { + (Size::S64, Location::Memory(base, disp), Location::GPR(dst)) => { + if disp >= 0 { + dynasm!($assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!($assembler ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } dynasm!($assembler - ; ldr x_tmp1, [X(map_gpr(src).x()), disp as u32] + ; ldr x_tmp1, [x_tmp3] ; $ins X(map_gpr(dst).x()), X(map_gpr(dst).x()), x_tmp1 ) }, @@ -273,22 +303,30 @@ macro_rules! binop_shift { }, (Size::S32, Location::Imm8(imm), Location::Memory(base, disp)) => { assert!(imm < 32); - assert!(disp >= 0); + if disp >= 0 { + dynasm!($assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!($assembler ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } dynasm!($assembler - ; ldr w_tmp1, [X(map_gpr(base).x()), disp as u32] + ; ldr w_tmp1, [x_tmp3] ; $ins w_tmp1, w_tmp1, imm as u32 - ; str w_tmp1, [X(map_gpr(base).x()), disp as u32] + ; str w_tmp1, [x_tmp3] ); }, (Size::S32, Location::GPR(GPR::RCX), Location::GPR(dst)) => { dynasm!($assembler ; $ins W(map_gpr(dst).x()), W(map_gpr(dst).x()), W(map_gpr(GPR::RCX).x())); }, (Size::S32, Location::GPR(GPR::RCX), Location::Memory(base, disp)) => { - assert!(disp >= 0); + if disp >= 0 { + dynasm!($assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!($assembler ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } dynasm!($assembler - ; ldr w_tmp1, [X(map_gpr(base).x()), disp as u32] + ; ldr w_tmp1, [x_tmp3] ; $ins w_tmp1, w_tmp1, W(map_gpr(GPR::RCX).x()) - ; str w_tmp1, [X(map_gpr(base).x()), disp as u32] + ; str w_tmp1, [x_tmp3] ); }, (Size::S64, Location::Imm8(imm), Location::GPR(dst)) => { @@ -297,22 +335,30 @@ macro_rules! binop_shift { }, (Size::S64, Location::Imm8(imm), Location::Memory(base, disp)) => { assert!(imm < 32); - assert!(disp >= 0); + if disp >= 0 { + dynasm!($assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!($assembler ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } dynasm!($assembler - ; ldr x_tmp1, [X(map_gpr(base).x()), disp as u32] + ; ldr x_tmp1, [x_tmp3] ; $ins x_tmp1, x_tmp1, imm as u32 - ; str x_tmp1, [X(map_gpr(base).x()), disp as u32] + ; str x_tmp1, [x_tmp3] ); }, (Size::S64, Location::GPR(GPR::RCX), Location::GPR(dst)) => { dynasm!($assembler ; $ins X(map_gpr(dst).x()), X(map_gpr(dst).x()), X(map_gpr(GPR::RCX).x())); }, (Size::S64, Location::GPR(GPR::RCX), Location::Memory(base, disp)) => { - assert!(disp >= 0); + if disp >= 0 { + dynasm!($assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!($assembler ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } dynasm!($assembler - ; ldr x_tmp1, [X(map_gpr(base).x()), disp as u32] + ; ldr x_tmp1, [x_tmp3] ; $ins x_tmp1, x_tmp1, X(map_gpr(GPR::RCX).x()) - ; str x_tmp1, [X(map_gpr(base).x()), disp as u32] + ; str x_tmp1, [x_tmp3] ); }, _ => $otherwise @@ -332,6 +378,10 @@ impl Emitter for Assembler { self.offset() } + fn get_jmp_instr_size(&self) -> u8 { + 4 + } + fn emit_u64(&mut self, x: u64) { self.push_u64(x); } @@ -349,17 +399,29 @@ impl Emitter for Assembler { (Size::S32, Location::GPR(src), Location::GPR(dst)) => { dynasm!(self ; mov W(map_gpr(dst).x()), W(map_gpr(src).x())); } - (Size::S32, Location::Memory(src, disp), Location::GPR(dst)) => { - assert!(disp >= 0); - dynasm!(self ; ldr W(map_gpr(dst).x()), [ X(map_gpr(src).x()), disp as u32 ] ); + (Size::S32, Location::Memory(base, disp), Location::GPR(dst)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; ldr W(map_gpr(dst).x()), [x_tmp3] ); } - (Size::S32, Location::GPR(src), Location::Memory(dst, disp)) => { - assert!(disp >= 0); - dynasm!(self ; str W(map_gpr(src).x()), [ X(map_gpr(dst).x()), disp as u32 ] ); + (Size::S32, Location::GPR(src), Location::Memory(base, disp)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; str W(map_gpr(src).x()), [x_tmp3] ); } - (Size::S32, Location::Imm32(x), Location::Memory(dst, disp)) => { - assert!(disp >= 0); - dynasm!(self ; b >after; data: ; .dword x as i32; after: ; ldr w_tmp1, { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; b >after; data: ; .dword x as i32; after: ; ldr w_tmp1, { dynasm!(self ; b >after; data: ; .dword x as i32; after: ; ldr W(map_gpr(dst).x()), { dynasm!(self ; mov X(map_gpr(dst).x()), X(map_gpr(src).x())); } - (Size::S64, Location::Memory(src, disp), Location::GPR(dst)) => { - assert!(disp >= 0); - dynasm!(self ; ldr X(map_gpr(dst).x()), [ X(map_gpr(src).x()), disp as u32 ] ); + (Size::S64, Location::Memory(base, disp), Location::GPR(dst)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; ldr X(map_gpr(dst).x()), [x_tmp3] ); } - (Size::S64, Location::GPR(src), Location::Memory(dst, disp)) => { - assert!(disp >= 0); - dynasm!(self ; str X(map_gpr(src).x()), [ X(map_gpr(dst).x()), disp as u32 ] ); + (Size::S64, Location::GPR(src), Location::Memory(base, disp)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; str X(map_gpr(src).x()), [x_tmp3] ); } - (Size::S64, Location::Imm32(x), Location::Memory(dst, disp)) => { - assert!(disp >= 0); - dynasm!(self ; b >after; data: ; .qword x as i64; after: ; ldr x_tmp1, { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; b >after; data: ; .qword x as i64; after: ; ldr x_tmp1, { dynasm!(self ; b >after; data: ; .qword x as i64; after: ; ldr X(map_gpr(dst).x()), unimplemented!(), + (Size::S64, Location::Imm64(x), Location::GPR(dst)) => { + dynasm!(self ; b >after; data: ; .qword x as i64; after: ; ldr X(map_gpr(dst).x()), { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; strb W(map_gpr(src).x()), [x_tmp3] ); + } + (Size::S8, Location::Memory(base, disp), Location::GPR(dst)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; ldrb W(map_gpr(dst).x()), [x_tmp3] ); + } + (Size::S8, Location::Imm32(x), Location::Memory(base, disp)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; b >after; data: ; .dword x as i32; after: ; ldr w_tmp1, { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; strh W(map_gpr(src).x()), [x_tmp3] ); + } + (Size::S16, Location::Memory(base, disp), Location::GPR(dst)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; ldrh W(map_gpr(dst).x()), [x_tmp3] ); + } + (Size::S16, Location::Imm32(x), Location::Memory(base, disp)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; b >after; data: ; .dword x as i32; after: ; ldr w_tmp1, { + dynasm!(self ; brk 21); + } + (_, _, Location::XMM(_)) => { + dynasm!(self ; brk 22); + } + _ => panic!("NOT IMPL: {:?} {:?} {:?}", sz, src, dst) } } @@ -480,8 +611,12 @@ impl Emitter for Assembler { match loc { Location::GPR(x) => dynasm!(self ; br X(map_gpr(x).x())), Location::Memory(base, disp) => { - assert!(disp >= 0); - dynasm!(self ; ldr x_tmp1, [ X(map_gpr(base).x()), disp as u32 ]; br x_tmp1); + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; ldr x_tmp1, [x_tmp3]; br x_tmp1); } _ => unreachable!(), } @@ -555,10 +690,14 @@ impl Emitter for Assembler { ; sub x_rsp, x_rsp, 8 ; str X(map_gpr(src).x()), [x_rsp] ), - (Size::S64, Location::Memory(src, disp)) => { - assert!(disp >= 0); + (Size::S64, Location::Memory(base, disp)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } dynasm!(self - ; ldr x_tmp1, [X(map_gpr(src).x()), disp as u32] + ; ldr x_tmp1, [x_tmp3] ; sub x_rsp, x_rsp, 8 ; str x_tmp1, [x_rsp] ); @@ -572,12 +711,16 @@ impl Emitter for Assembler { ; ldr X(map_gpr(dst).x()), [x_rsp] ; add x_rsp, x_rsp, 8 ), - (Size::S64, Location::Memory(dst, disp)) => { - assert!(disp >= 0); + (Size::S64, Location::Memory(base, disp)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } dynasm!(self ; ldr x_tmp1, [x_rsp] ; add x_rsp, x_rsp, 8 - ; str x_tmp1, [X(map_gpr(dst).x()), disp as u32] + ; str x_tmp1, [x_tmp3] ); } _ => panic!("pop {:?} {:?}", sz, dst), @@ -605,27 +748,35 @@ impl Emitter for Assembler { ; cmp X(map_gpr(right).x()), x_tmp1 ); } - (Size::S32, Location::Imm32(left), Location::Memory(right, disp)) => { - assert!(disp >= 0); + (Size::S32, Location::Imm32(left), Location::Memory(base, disp)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } dynasm!(self ; b >after ; data: ; .dword left as i32 ; after: ; ldr w_tmp1, { - assert!(disp >= 0); + (Size::S64, Location::Imm32(left), Location::Memory(base, disp)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } dynasm!(self ; b >after ; data: ; .qword left as i64 ; after: ; ldr x_tmp1, dynasm!( - self - ; ldr w_tmp1, [X(map_gpr(right).x()), disp as u32] - ; cmp w_tmp1, W(map_gpr(left).x()) - ), - (Size::S64, Location::GPR(left), Location::Memory(right, disp)) => dynasm!( - self - ; ldr x_tmp1, [X(map_gpr(right).x()), disp as u32] - ; cmp x_tmp1, X(map_gpr(left).x()) - ), - (Size::S32, Location::Memory(left, disp), Location::GPR(right)) => dynasm!( - self - ; ldr w_tmp1, [X(map_gpr(left).x()), disp as u32] - ; cmp W(map_gpr(right).x()), w_tmp1 - ), - (Size::S64, Location::Memory(left, disp), Location::GPR(right)) => dynasm!( - self - ; ldr x_tmp1, [X(map_gpr(left).x()), disp as u32] - ; cmp X(map_gpr(right).x()), x_tmp1 - ), + (Size::S32, Location::GPR(left), Location::Memory(base, disp)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!( + self + ; ldr w_tmp1, [x_tmp3] + ; cmp w_tmp1, W(map_gpr(left).x()) + ) + }, + (Size::S64, Location::GPR(left), Location::Memory(base, disp)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!( + self + ; ldr x_tmp1, [x_tmp3] + ; cmp x_tmp1, X(map_gpr(left).x()) + ) + }, + (Size::S32, Location::Memory(base, disp), Location::GPR(right)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!( + self + ; ldr w_tmp1, [x_tmp3] + ; cmp W(map_gpr(right).x()), w_tmp1 + ) + }, + (Size::S64, Location::Memory(base, disp), Location::GPR(right)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!( + self + ; ldr x_tmp1, [x_tmp3] + ; cmp X(map_gpr(right).x()), x_tmp1 + ) + }, _ => unreachable!(), } } @@ -693,10 +872,14 @@ impl Emitter for Assembler { ; mov w_tmp1, W(map_gpr(x).x()) ), Location::Memory(base, disp) => { - assert!(disp >= 0); + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } dynasm!( self - ; ldr w_tmp1, [X(map_gpr(base).x()), disp as u32] + ; ldr w_tmp1, [x_tmp3] ) } _ => unreachable!() @@ -715,10 +898,14 @@ impl Emitter for Assembler { ; mov x_tmp1, X(map_gpr(x).x()) ), Location::Memory(base, disp) => { - assert!(disp >= 0); + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } dynasm!( self - ; ldr x_tmp1, [X(map_gpr(base).x()), disp as u32] + ; ldr x_tmp1, [x_tmp3] ) } _ => unreachable!() @@ -742,10 +929,14 @@ impl Emitter for Assembler { ; mov w_tmp1, W(map_gpr(x).x()) ), Location::Memory(base, disp) => { - assert!(disp >= 0); + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } dynasm!( self - ; ldr w_tmp1, [X(map_gpr(base).x()), disp as u32] + ; ldr w_tmp1, [x_tmp3] ) } _ => unreachable!() @@ -764,10 +955,14 @@ impl Emitter for Assembler { ; mov x_tmp1, X(map_gpr(x).x()) ), Location::Memory(base, disp) => { - assert!(disp >= 0); + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } dynasm!( self - ; ldr x_tmp1, [X(map_gpr(base).x()), disp as u32] + ; ldr x_tmp1, [x_tmp3] ) } _ => unreachable!() @@ -861,13 +1056,21 @@ impl Emitter for Assembler { (Size::S16, Location::GPR(src), Location::GPR(dst)) => { dynasm!(self ; uxth W(map_gpr(dst).x()), W(map_gpr(src).x())); } - (Size::S8, Location::Memory(src, disp), Location::GPR(dst)) => { - assert!(disp >= 0); - dynasm!(self ; ldrb W(map_gpr(dst).x()), [X(map_gpr(src).x()), disp as u32]); + (Size::S8, Location::Memory(base, disp), Location::GPR(dst)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; ldrb W(map_gpr(dst).x()), [x_tmp3]); } - (Size::S16, Location::Memory(src, disp), Location::GPR(dst)) => { - assert!(disp >= 0); - dynasm!(self ; ldrh W(map_gpr(dst).x()), [X(map_gpr(src).x()), disp as u32]); + (Size::S16, Location::Memory(base, disp), Location::GPR(dst)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; ldrh W(map_gpr(dst).x()), [x_tmp3]); } _ => unreachable!(), } @@ -880,13 +1083,21 @@ impl Emitter for Assembler { (Size::S16, Location::GPR(src), Size::S32, Location::GPR(dst)) => { dynasm!(self ; sxth W(map_gpr(dst).x()), W(map_gpr(src).x())); } - (Size::S8, Location::Memory(src, disp), Size::S32, Location::GPR(dst)) => { - assert!(disp >= 0); - dynasm!(self ; ldrb W(map_gpr(dst).x()), [X(map_gpr(src).x()), disp as u32]; sxtb W(map_gpr(dst).x()), W(map_gpr(dst).x())); + (Size::S8, Location::Memory(base, disp), Size::S32, Location::GPR(dst)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; ldrb W(map_gpr(dst).x()), [x_tmp3]; sxtb W(map_gpr(dst).x()), W(map_gpr(dst).x())); } - (Size::S16, Location::Memory(src, disp), Size::S32, Location::GPR(dst)) => { - assert!(disp >= 0); - dynasm!(self ; ldrh W(map_gpr(dst).x()), [X(map_gpr(src).x()), disp as u32]; sxth W(map_gpr(dst).x()), W(map_gpr(dst).x())); + (Size::S16, Location::Memory(base, disp), Size::S32, Location::GPR(dst)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; ldrh W(map_gpr(dst).x()), [x_tmp3]; sxth W(map_gpr(dst).x()), W(map_gpr(dst).x())); } (Size::S8, Location::GPR(src), Size::S64, Location::GPR(dst)) => { dynasm!(self ; sxtb X(map_gpr(dst).x()), W(map_gpr(src).x())); @@ -897,17 +1108,29 @@ impl Emitter for Assembler { (Size::S32, Location::GPR(src), Size::S64, Location::GPR(dst)) => { dynasm!(self ; sxtw X(map_gpr(dst).x()), W(map_gpr(src).x())); } - (Size::S8, Location::Memory(src, disp), Size::S64, Location::GPR(dst)) => { - assert!(disp >= 0); - dynasm!(self ; ldrb W(map_gpr(dst).x()), [X(map_gpr(src).x()), disp as u32]; sxtb X(map_gpr(dst).x()), W(map_gpr(dst).x())); + (Size::S8, Location::Memory(base, disp), Size::S64, Location::GPR(dst)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; ldrb W(map_gpr(dst).x()), [x_tmp3]; sxtb X(map_gpr(dst).x()), W(map_gpr(dst).x())); } - (Size::S16, Location::Memory(src, disp), Size::S64, Location::GPR(dst)) => { - assert!(disp >= 0); - dynasm!(self ; ldrh W(map_gpr(dst).x()), [X(map_gpr(src).x()), disp as u32]; sxth X(map_gpr(dst).x()), W(map_gpr(dst).x())); + (Size::S16, Location::Memory(base, disp), Size::S64, Location::GPR(dst)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; ldrh W(map_gpr(dst).x()), [x_tmp3]; sxth X(map_gpr(dst).x()), W(map_gpr(dst).x())); } - (Size::S32, Location::Memory(src, disp), Size::S64, Location::GPR(dst)) => { - assert!(disp >= 0); - dynasm!(self ; ldrh W(map_gpr(dst).x()), [X(map_gpr(src).x()), disp as u32]; sxtw X(map_gpr(dst).x()), W(map_gpr(dst).x())); + (Size::S32, Location::Memory(base, disp), Size::S64, Location::GPR(dst)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; ldrh W(map_gpr(dst).x()), [x_tmp3]; sxtw X(map_gpr(dst).x()), W(map_gpr(dst).x())); } _ => unreachable!(), } @@ -915,171 +1138,171 @@ impl Emitter for Assembler { // TODO: These instructions are only used in FP opcodes. Implement later. fn emit_btc_gpr_imm8_32(&mut self, src: u8, dst: GPR) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_btc_gpr_imm8_64(&mut self, src: u8, dst: GPR) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_cmovae_gpr_32(&mut self, src: GPR, dst: GPR) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_cmovae_gpr_64(&mut self, src: GPR, dst: GPR) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vaddss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vaddsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vsubss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vsubsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vmulss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vmulsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vdivss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vdivsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vmaxss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vmaxsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vminss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vminsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vcmpeqss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vcmpeqsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vcmpneqss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vcmpneqsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vcmpltss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vcmpltsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vcmpless(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vcmplesd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vcmpgtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vcmpgtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vcmpgess(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vcmpgesd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vsqrtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vsqrtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vroundss_nearest(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vroundss_floor(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vroundss_ceil(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vroundss_trunc(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vroundsd_nearest(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vroundsd_floor(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vroundsd_ceil(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vroundsd_trunc(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vcvtss2sd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vcvtsd2ss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_ucomiss(&mut self, src: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_ucomisd(&mut self, src: XMMOrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_cvttss2si_32(&mut self, src: XMMOrMemory, dst: GPR) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_cvttss2si_64(&mut self, src: XMMOrMemory, dst: GPR) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_cvttsd2si_32(&mut self, src: XMMOrMemory, dst: GPR) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_cvttsd2si_64(&mut self, src: XMMOrMemory, dst: GPR) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vcvtsi2ss_32(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vcvtsi2ss_64(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vcvtsi2sd_32(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_vcvtsi2sd_64(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_test_gpr_64(&mut self, reg: GPR) { - unimplemented!("instruction") + dynasm!(self ; brk 29) } fn emit_ud2(&mut self) { @@ -1127,7 +1350,11 @@ impl Emitter for Assembler { ; done: ), Location::Memory(base, disp) => { - assert!(disp >= 0); + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } dynasm!(self // Push return address. ; sub x_rsp, x_rsp, 8 @@ -1135,7 +1362,7 @@ impl Emitter for Assembler { ; str x_tmp1, [x_rsp] // Read memory. - ; ldr x_tmp1, [X(map_gpr(base).x()), disp as u32] + ; ldr x_tmp1, [x_tmp3] // Jump. ; br x_tmp1 @@ -1154,6 +1381,7 @@ impl Emitter for Assembler { let target = map_gpr(target); dynasm!( self + ; bkpt 16 ; sub sp, sp, 80 ; str x30, [sp, 0] // LR ; str X(target.x()), [sp, 8] @@ -1200,6 +1428,7 @@ impl Emitter for Assembler { ; ldr x_tmp1, [x_rsp] ; add x_rsp, x_rsp, 8 + ; bkpt 17 ; br x_tmp1 ); } @@ -1216,10 +1445,14 @@ fn emit_clz_variant(assembler: &mut Assembler, sz: Size, src: &Location, dst: &L ) } Location::Memory(base, disp) => { - assert!(disp >= 0); + if disp >= 0 { + dynasm!(assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(assembler ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } dynasm!( assembler - ; ldr w_tmp1, [X(map_gpr(base).x()), disp as u32] + ; ldr w_tmp1, [x_tmp3] ) } _ => unreachable!() @@ -1246,10 +1479,14 @@ fn emit_clz_variant(assembler: &mut Assembler, sz: Size, src: &Location, dst: &L ) } Location::Memory(base, disp) => { - assert!(disp >= 0); + if disp >= 0 { + dynasm!(assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(assembler ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } dynasm!( assembler - ; ldr x_tmp1, [X(map_gpr(base).x()), disp as u32] + ; ldr x_tmp1, [x_tmp3] ) } _ => unreachable!() From b3043176823613abadf27a8d763ad83d77cfbc7f Mon Sep 17 00:00:00 2001 From: losfair Date: Mon, 30 Sep 2019 01:01:15 +0800 Subject: [PATCH 019/342] More mov variants. --- .../src/translator_aarch64.rs | 54 ++++++++++++++++--- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index c01384553e2..331d33779fe 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -507,11 +507,55 @@ impl Emitter for Assembler { } dynasm!(self ; b >after; data: ; .dword x as i32; after: ; ldr w_tmp1, { - dynasm!(self ; brk 21); + (Size::S32, Location::XMM(src), Location::XMM(dst)) => { + dynasm!(self ; fmov S(map_xmm(dst).v()), S(map_xmm(src).v())); } - (_, _, Location::XMM(_)) => { - dynasm!(self ; brk 22); + (Size::S32, Location::XMM(src), Location::GPR(dst)) => { + dynasm!(self ; fmov W(map_gpr(dst).x()), S(map_xmm(src).v())); + } + (Size::S32, Location::GPR(src), Location::XMM(dst)) => { + dynasm!(self ; fmov S(map_xmm(dst).v()), W(map_gpr(src).x())); + } + (Size::S32, Location::Memory(base, disp), Location::XMM(dst)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; ldr S(map_xmm(dst).v()), [x_tmp3] ); + } + (Size::S32, Location::XMM(src), Location::Memory(base, disp)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; str S(map_xmm(src).v()), [x_tmp3] ); + } + (Size::S64, Location::XMM(src), Location::XMM(dst)) => { + dynasm!(self ; fmov D(map_xmm(dst).v()), D(map_xmm(src).v())); + } + (Size::S64, Location::XMM(src), Location::GPR(dst)) => { + dynasm!(self ; fmov X(map_gpr(dst).x()), D(map_xmm(src).v())); + } + (Size::S64, Location::GPR(src), Location::XMM(dst)) => { + dynasm!(self ; fmov D(map_xmm(dst).v()), X(map_gpr(src).x())); + } + (Size::S64, Location::Memory(base, disp), Location::XMM(dst)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; ldr D(map_xmm(dst).v()), [x_tmp3] ); + } + (Size::S64, Location::XMM(src), Location::Memory(base, disp)) => { + if disp >= 0 { + dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(self ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); + } + dynasm!(self ; str D(map_xmm(src).v()), [x_tmp3] ); } _ => panic!("NOT IMPL: {:?} {:?} {:?}", sz, src, dst) } @@ -1381,7 +1425,6 @@ impl Emitter for Assembler { let target = map_gpr(target); dynasm!( self - ; bkpt 16 ; sub sp, sp, 80 ; str x30, [sp, 0] // LR ; str X(target.x()), [sp, 8] @@ -1428,7 +1471,6 @@ impl Emitter for Assembler { ; ldr x_tmp1, [x_rsp] ; add x_rsp, x_rsp, 8 - ; bkpt 17 ; br x_tmp1 ); } From 80d6c4cbc0ff5436491e4f9969d0cc64dc3189eb Mon Sep 17 00:00:00 2001 From: losfair Date: Sun, 6 Oct 2019 18:27:35 +0800 Subject: [PATCH 020/342] Implement get_fault_info for aarch64. --- lib/runtime-core/src/fault.rs | 64 +++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index e6fc8e400de..d3422d55e14 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -246,6 +246,7 @@ extern "C" fn signal_trap_handler( ) { unsafe { let fault = get_fault_info(siginfo as _, ucontext); + println!("Fault: {:?}", fault); let mut unwind_result: Box = Box::new(()); @@ -368,15 +369,74 @@ unsafe fn install_sighandler() { sigaction(SIGINT, &sa_interrupt).unwrap(); } +#[derive(Debug, Clone)] pub struct FaultInfo { pub faulting_addr: *const c_void, pub ip: *const c_void, pub known_registers: [Option; 24], } -#[cfg(target_arch = "aarch64")] +#[cfg(all(target_os = "linux", target_arch = "aarch64"))] pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> FaultInfo { - unimplemented!("get_fault_info is not yet implemented for aarch64."); + #[allow(dead_code)] + #[repr(packed)] + struct sigcontext { + fault_address: u64, + regs: [u64; 31], + sp: u64, + pc: u64, + pstate: u64, + reserved: [u8; 4096], + } + + #[allow(dead_code)] + #[repr(packed)] + struct ucontext { + unknown: [u8; 176], + uc_mcontext: sigcontext, + } + + #[allow(dead_code)] + #[repr(C)] + struct siginfo_t { + si_signo: i32, + si_errno: i32, + si_code: i32, + si_addr: u64, + // ... + } + + let siginfo = siginfo as *const siginfo_t; + let si_addr = (*siginfo).si_addr; + + let ucontext = ucontext as *const ucontext; + let gregs = &(*ucontext).uc_mcontext.regs; + + let mut known_registers: [Option; 24] = [None; 24]; + + known_registers[X64Register::GPR(GPR::R15).to_index().0] = Some(gregs[15] as _); + known_registers[X64Register::GPR(GPR::R14).to_index().0] = Some(gregs[14] as _); + known_registers[X64Register::GPR(GPR::R13).to_index().0] = Some(gregs[13] as _); + known_registers[X64Register::GPR(GPR::R12).to_index().0] = Some(gregs[12] as _); + known_registers[X64Register::GPR(GPR::R11).to_index().0] = Some(gregs[11] as _); + known_registers[X64Register::GPR(GPR::R10).to_index().0] = Some(gregs[10] as _); + known_registers[X64Register::GPR(GPR::R9).to_index().0] = Some(gregs[9] as _); + known_registers[X64Register::GPR(GPR::R8).to_index().0] = Some(gregs[8] as _); + known_registers[X64Register::GPR(GPR::RSI).to_index().0] = Some(gregs[6] as _); + known_registers[X64Register::GPR(GPR::RDI).to_index().0] = Some(gregs[7] as _); + known_registers[X64Register::GPR(GPR::RDX).to_index().0] = Some(gregs[2] as _); + known_registers[X64Register::GPR(GPR::RCX).to_index().0] = Some(gregs[1] as _); + known_registers[X64Register::GPR(GPR::RBX).to_index().0] = Some(gregs[3] as _); + known_registers[X64Register::GPR(GPR::RAX).to_index().0] = Some(gregs[0] as _); + + known_registers[X64Register::GPR(GPR::RBP).to_index().0] = Some(gregs[5] as _); + known_registers[X64Register::GPR(GPR::RSP).to_index().0] = Some(gregs[28] as _); + + FaultInfo { + faulting_addr: si_addr as usize as _, + ip: (*ucontext).uc_mcontext.pc as _, + known_registers, + } } #[cfg(all(target_os = "linux", target_arch = "x86_64"))] From 6ca581279811aee9d26d77ed2b7372a6153fe3bf Mon Sep 17 00:00:00 2001 From: Yaron Wittenstein Date: Mon, 7 Oct 2019 16:58:58 +0300 Subject: [PATCH 021/342] When `deterministic` feature will be enabled (turned-off by default) it'll guarantee deterministic execution of wasm programs across different hardware/circumstances. This is very useful for Blockchain projects having wasm smart-contracts This is critical for Blockchain projects that require execution to be deterministic in order to reach a consensus of the state transition of each smart-contract transaction. --- Cargo.toml | 4 +++- lib/runtime-core/Cargo.toml | 1 + lib/runtime-core/src/codegen.rs | 3 +++ lib/runtime-core/src/lib.rs | 3 +++ lib/runtime/Cargo.toml | 1 + lib/runtime/src/lib.rs | 12 +++++++----- lib/singlepass-backend/Cargo.toml | 4 ++++ 7 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4d619059e35..93479c41598 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ wabt = "0.9.1" wasmer-clif-backend = { path = "lib/clif-backend" } wasmer-singlepass-backend = { path = "lib/singlepass-backend", optional = true } wasmer-middleware-common = { path = "lib/middleware-common" } -wasmer-runtime = { path = "lib/runtime" } +wasmer-runtime = { path = "lib/runtime", default-features = false } wasmer-runtime-core = { path = "lib/runtime-core" } wasmer-emscripten = { path = "lib/emscripten" } wasmer-llvm-backend = { path = "lib/llvm-backend", optional = true } @@ -101,6 +101,8 @@ backend-singlepass = [ wasi = ["wasmer-wasi"] managed = ["backend-singlepass", "wasmer-runtime-core/managed"] +deterministic = ["wasmer-runtime/deterministic"] + [[example]] name = "plugin" crate-type = ["bin"] diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml index 7fd9e32e835..ee1fd19ebff 100644 --- a/lib/runtime-core/Cargo.toml +++ b/lib/runtime-core/Cargo.toml @@ -58,3 +58,4 @@ trace = ["debug"] "backend-singlepass" = [] "backend-llvm" = [] managed = [] +deterministic = ["wasmparser/deterministic"] diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index 3db1b374368..7027d6266a3 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -145,6 +145,9 @@ pub fn validating_parser_config(features: &Features) -> wasmparser::ValidatingPa enable_simd: features.simd, enable_bulk_memory: false, enable_multi_value: false, + + #[cfg(feature = "deterministic")] + deterministic_only: true, }, } } diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index 26a76f7dbf6..d933b555f30 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -145,6 +145,9 @@ pub fn validate_and_report_errors_with_features( enable_multi_value: false, enable_reference_types: false, enable_threads: features.threads, + + #[cfg(feature = "deterministic")] + deterministic_only: true, }, }; let mut parser = wasmparser::ValidatingParser::new(wasm, Some(config)); diff --git a/lib/runtime/Cargo.toml b/lib/runtime/Cargo.toml index 2e42055c2e4..a3a59f7e50e 100644 --- a/lib/runtime/Cargo.toml +++ b/lib/runtime/Cargo.toml @@ -41,6 +41,7 @@ singlepass = ["wasmer-singlepass-backend"] default-backend-singlepass = ["singlepass"] default-backend-llvm = ["llvm"] default-backend-cranelift = ["cranelift"] +deterministic = ["wasmer-singlepass-backend/deterministic"] [[bench]] name = "nginx" diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index 2945ff3d534..3505de6492d 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -70,7 +70,7 @@ //! let value = add_one.call(42)?; //! //! assert_eq!(value, 43); -//! +//! //! Ok(()) //! } //! ``` @@ -199,13 +199,15 @@ pub fn default_compiler() -> impl Compiler { feature = "default-backend-llvm", any( feature = "default-backend-cranelift", - feature = "default-backend-singlepass" + feature = "default-backend-singlepass", + feature = "deterministic" ) ), all( feature = "default-backend-cranelift", - feature = "default-backend-singlepass" - ) + any(feature = "default-backend-singlepass", feature = "deterministic") + ), + all(feature = "default-backend-singlepass", feature = "deterministic") ))] compile_error!( "The `default-backend-X` features are mutually exclusive. Please choose just one" @@ -214,7 +216,7 @@ pub fn default_compiler() -> impl Compiler { #[cfg(feature = "default-backend-llvm")] use wasmer_llvm_backend::LLVMCompiler as DefaultCompiler; - #[cfg(feature = "default-backend-singlepass")] + #[cfg(any(feature = "default-backend-singlepass", feature = "deterministic"))] use wasmer_singlepass_backend::SinglePassCompiler as DefaultCompiler; #[cfg(feature = "default-backend-cranelift")] diff --git a/lib/singlepass-backend/Cargo.toml b/lib/singlepass-backend/Cargo.toml index 5243cc60150..d6dc63c7a2d 100644 --- a/lib/singlepass-backend/Cargo.toml +++ b/lib/singlepass-backend/Cargo.toml @@ -18,3 +18,7 @@ byteorder = "1.3" nix = "0.15" libc = "0.2.60" smallvec = "0.6" + +[features] +default = [] +deterministic = ["wasmparser/deterministic", "wasmer-runtime-core/deterministic"] From e0e7d58313a5d066587bab5a76412e9064e7df98 Mon Sep 17 00:00:00 2001 From: losfair Date: Mon, 7 Oct 2019 23:00:37 +0800 Subject: [PATCH 022/342] Make state mapping work on non-x86 architectures. --- lib/runtime-core/src/fault.rs | 2 +- lib/runtime-core/src/instance.rs | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index d3422d55e14..75b92bb23b8 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -198,7 +198,7 @@ unsafe fn with_breakpoint_map) -> R>(f: F) - #[cfg(not(target_arch = "x86_64"))] pub fn allocate_and_run R>(size: usize, f: F) -> R { - unimplemented!("allocate_and_run only supported on x86_64"); + f() } #[cfg(target_arch = "x86_64")] diff --git a/lib/runtime-core/src/instance.rs b/lib/runtime-core/src/instance.rs index e6ba365f6ef..38ac2ab8f4d 100644 --- a/lib/runtime-core/src/instance.rs +++ b/lib/runtime-core/src/instance.rs @@ -3,6 +3,7 @@ use crate::{ backing::{ImportBacking, LocalBacking}, error::{CallError, CallResult, ResolveError, ResolveResult, Result, RuntimeError}, export::{Context, Export, ExportIter, FuncPointer}, + fault::{pop_code_version, push_code_version}, global::Global, import::{ImportObject, LikeNamespace}, loader::Loader, @@ -11,6 +12,7 @@ use crate::{ sig_registry::SigRegistry, structures::TypedIndex, table::Table, + state::CodeVersion, typed_func::{Func, Wasm, WasmTrapInfo, WasmTypeList}, types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Type, Value}, vm::{self, InternalField}, @@ -333,7 +335,13 @@ impl Instance { let mut results = Vec::new(); - call_func_with_index( + push_code_version(CodeVersion { + baseline: true, + msm: self.module.runnable_module.get_module_state_map().unwrap(), + base: self.module.runnable_module.get_code().unwrap().as_ptr() as usize, + }); + + let result = call_func_with_index( &self.module.info, &*self.module.runnable_module, &self.inner.import_backing, @@ -341,7 +349,10 @@ impl Instance { func_index, params, &mut results, - )?; + ); + + pop_code_version().unwrap(); + result?; Ok(results) } From 7ce5ec4df9ad6056b77389321003229253cddaa8 Mon Sep 17 00:00:00 2001 From: Yaron Wittenstein Date: Mon, 7 Oct 2019 22:34:32 +0300 Subject: [PATCH 023/342] fixes to PR comments --- Cargo.toml | 3 +-- lib/runtime/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 93479c41598..467e65419e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ wabt = "0.9.1" wasmer-clif-backend = { path = "lib/clif-backend" } wasmer-singlepass-backend = { path = "lib/singlepass-backend", optional = true } wasmer-middleware-common = { path = "lib/middleware-common" } -wasmer-runtime = { path = "lib/runtime", default-features = false } +wasmer-runtime = { path = "lib/runtime" } wasmer-runtime-core = { path = "lib/runtime-core" } wasmer-emscripten = { path = "lib/emscripten" } wasmer-llvm-backend = { path = "lib/llvm-backend", optional = true } @@ -100,7 +100,6 @@ backend-singlepass = [ ] wasi = ["wasmer-wasi"] managed = ["backend-singlepass", "wasmer-runtime-core/managed"] - deterministic = ["wasmer-runtime/deterministic"] [[example]] diff --git a/lib/runtime/Cargo.toml b/lib/runtime/Cargo.toml index a3a59f7e50e..838eed3ce57 100644 --- a/lib/runtime/Cargo.toml +++ b/lib/runtime/Cargo.toml @@ -41,7 +41,7 @@ singlepass = ["wasmer-singlepass-backend"] default-backend-singlepass = ["singlepass"] default-backend-llvm = ["llvm"] default-backend-cranelift = ["cranelift"] -deterministic = ["wasmer-singlepass-backend/deterministic"] +deterministic = ["wasmer-singlepass-backend/deterministic", "wasmer-runtime-core/deterministic"] [[bench]] name = "nginx" From 899099f3256a1c9ced175d9864da6a7ca5166cd7 Mon Sep 17 00:00:00 2001 From: Yaron Wittenstein Date: Mon, 7 Oct 2019 22:58:46 +0300 Subject: [PATCH 024/342] Cargo.toml - removing `deterministic` feature flag --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 467e65419e5..4d619059e35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -100,7 +100,6 @@ backend-singlepass = [ ] wasi = ["wasmer-wasi"] managed = ["backend-singlepass", "wasmer-runtime-core/managed"] -deterministic = ["wasmer-runtime/deterministic"] [[example]] name = "plugin" From 3489bfb9b9814f84424b63cff7dec297a6a4f1d6 Mon Sep 17 00:00:00 2001 From: Yaron Wittenstein Date: Mon, 7 Oct 2019 23:07:20 +0300 Subject: [PATCH 025/342] renamed feature flag `deterministic` to `deterministic-execution` --- lib/runtime-core/Cargo.toml | 2 +- lib/runtime-core/src/codegen.rs | 2 +- lib/runtime-core/src/lib.rs | 2 +- lib/runtime/Cargo.toml | 2 +- lib/runtime/src/lib.rs | 22 ++++++++++++++++------ lib/singlepass-backend/Cargo.toml | 2 +- 6 files changed, 21 insertions(+), 11 deletions(-) diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml index ee1fd19ebff..f4f80d985c5 100644 --- a/lib/runtime-core/Cargo.toml +++ b/lib/runtime-core/Cargo.toml @@ -58,4 +58,4 @@ trace = ["debug"] "backend-singlepass" = [] "backend-llvm" = [] managed = [] -deterministic = ["wasmparser/deterministic"] +deterministic-execution = ["wasmparser/deterministic"] diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index 7027d6266a3..8d98bb0c0f9 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -146,7 +146,7 @@ pub fn validating_parser_config(features: &Features) -> wasmparser::ValidatingPa enable_bulk_memory: false, enable_multi_value: false, - #[cfg(feature = "deterministic")] + #[cfg(feature = "deterministic-execution")] deterministic_only: true, }, } diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index d933b555f30..accea76414d 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -146,7 +146,7 @@ pub fn validate_and_report_errors_with_features( enable_reference_types: false, enable_threads: features.threads, - #[cfg(feature = "deterministic")] + #[cfg(feature = "deterministic-execution")] deterministic_only: true, }, }; diff --git a/lib/runtime/Cargo.toml b/lib/runtime/Cargo.toml index 838eed3ce57..8ed986c5041 100644 --- a/lib/runtime/Cargo.toml +++ b/lib/runtime/Cargo.toml @@ -41,7 +41,7 @@ singlepass = ["wasmer-singlepass-backend"] default-backend-singlepass = ["singlepass"] default-backend-llvm = ["llvm"] default-backend-cranelift = ["cranelift"] -deterministic = ["wasmer-singlepass-backend/deterministic", "wasmer-runtime-core/deterministic"] +deterministic-execution = ["wasmer-singlepass-backend/deterministic-execution", "wasmer-runtime-core/deterministic-execution"] [[bench]] name = "nginx" diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index 3505de6492d..903dc47836e 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -200,14 +200,20 @@ pub fn default_compiler() -> impl Compiler { any( feature = "default-backend-cranelift", feature = "default-backend-singlepass", - feature = "deterministic" + feature = "deterministic-execution" ) ), all( feature = "default-backend-cranelift", - any(feature = "default-backend-singlepass", feature = "deterministic") + any( + feature = "default-backend-singlepass", + feature = "deterministic-execution" + ) ), - all(feature = "default-backend-singlepass", feature = "deterministic") + all( + feature = "default-backend-singlepass", + feature = "deterministic-execution" + ) ))] compile_error!( "The `default-backend-X` features are mutually exclusive. Please choose just one" @@ -216,7 +222,10 @@ pub fn default_compiler() -> impl Compiler { #[cfg(feature = "default-backend-llvm")] use wasmer_llvm_backend::LLVMCompiler as DefaultCompiler; - #[cfg(any(feature = "default-backend-singlepass", feature = "deterministic"))] + #[cfg(any( + feature = "default-backend-singlepass", + feature = "deterministic-execution" + ))] use wasmer_singlepass_backend::SinglePassCompiler as DefaultCompiler; #[cfg(feature = "default-backend-cranelift")] @@ -235,7 +244,7 @@ pub fn compiler_for_backend(backend: Backend) -> Option> { #[cfg(feature = "cranelift")] Backend::Cranelift => Some(Box::new(wasmer_clif_backend::CraneliftCompiler::new())), - #[cfg(feature = "singlepass")] + #[cfg(any(feature = "singlepass", feature = "deterministic-execution"))] Backend::Singlepass => Some(Box::new( wasmer_singlepass_backend::SinglePassCompiler::new(), )), @@ -246,7 +255,8 @@ pub fn compiler_for_backend(backend: Backend) -> Option> { #[cfg(any( not(feature = "llvm"), not(feature = "singlepass"), - not(feature = "cranelift") + not(feature = "cranelift"), + not(feature = "deterministic-execution"), ))] _ => None, } diff --git a/lib/singlepass-backend/Cargo.toml b/lib/singlepass-backend/Cargo.toml index d6dc63c7a2d..e3a40548ecd 100644 --- a/lib/singlepass-backend/Cargo.toml +++ b/lib/singlepass-backend/Cargo.toml @@ -21,4 +21,4 @@ smallvec = "0.6" [features] default = [] -deterministic = ["wasmparser/deterministic", "wasmer-runtime-core/deterministic"] +deterministic-execution = ["wasmparser/deterministic", "wasmer-runtime-core/deterministic-execution"] From b5bb3fa7642277088485be44881517f214dbdb33 Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 8 Oct 2019 18:41:22 +0800 Subject: [PATCH 026/342] Move {push,pop}_code_version to caller side for non-mananged execution. --- lib/runtime-core/src/instance.rs | 15 ++------------- src/bin/wasmer.rs | 11 +++++++++++ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/runtime-core/src/instance.rs b/lib/runtime-core/src/instance.rs index 38ac2ab8f4d..e6ba365f6ef 100644 --- a/lib/runtime-core/src/instance.rs +++ b/lib/runtime-core/src/instance.rs @@ -3,7 +3,6 @@ use crate::{ backing::{ImportBacking, LocalBacking}, error::{CallError, CallResult, ResolveError, ResolveResult, Result, RuntimeError}, export::{Context, Export, ExportIter, FuncPointer}, - fault::{pop_code_version, push_code_version}, global::Global, import::{ImportObject, LikeNamespace}, loader::Loader, @@ -12,7 +11,6 @@ use crate::{ sig_registry::SigRegistry, structures::TypedIndex, table::Table, - state::CodeVersion, typed_func::{Func, Wasm, WasmTrapInfo, WasmTypeList}, types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Type, Value}, vm::{self, InternalField}, @@ -335,13 +333,7 @@ impl Instance { let mut results = Vec::new(); - push_code_version(CodeVersion { - baseline: true, - msm: self.module.runnable_module.get_module_state_map().unwrap(), - base: self.module.runnable_module.get_code().unwrap().as_ptr() as usize, - }); - - let result = call_func_with_index( + call_func_with_index( &self.module.info, &*self.module.runnable_module, &self.inner.import_backing, @@ -349,10 +341,7 @@ impl Instance { func_index, params, &mut results, - ); - - pop_code_version().unwrap(); - result?; + )?; Ok(results) } diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 3bd4aa21cd8..f1e20328b30 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -630,7 +630,18 @@ fn execute_wasm(options: &Run) -> Result<(), String> { #[cfg(not(feature = "managed"))] { use wasmer_runtime::error::RuntimeError; + use wasmer_runtime_core::{ + fault::{push_code_version, pop_code_version}, + state::CodeVersion + }; + + push_code_version(CodeVersion { + baseline: true, + msm: instance.module.runnable_module.get_module_state_map().unwrap(), + base: instance.module.runnable_module.get_code().unwrap().as_ptr() as usize, + }); let result = start.call(); + pop_code_version().unwrap(); if let Err(ref err) = result { match err { From c337999c5c3ac33080f1df86497edd47be38ef14 Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 8 Oct 2019 18:43:39 +0800 Subject: [PATCH 027/342] x --- lib/runtime-core/src/fault.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index 75b92bb23b8..68148bb1c52 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -293,6 +293,7 @@ extern "C" fn signal_trap_handler( let es_image = CURRENT_CODE_VERSIONS.with(|versions| { let versions = versions.borrow(); + println!("V = {}", versions.len()); read_stack( || versions.iter(), rsp as usize as *const u64, @@ -306,6 +307,7 @@ extern "C" fn signal_trap_handler( unwind_result = Box::new(image); } else { use colored::*; + println!("F = {}", es_image.frames.len()); if es_image.frames.len() > 0 { eprintln!( "\n{}", From bd06aa02babef4f569d359de68f7fa822391d650 Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 8 Oct 2019 19:07:38 +0800 Subject: [PATCH 028/342] x --- lib/runtime-core/src/state.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index f61c6aa5c8e..1896c5c9e2a 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -889,6 +889,7 @@ pub mod x64 { let mut is_baseline: Option = None; for version in versions() { + println!("Lookup IP: {:x}", ret_addr); match version .msm .lookup_call_ip(ret_addr as usize, version.base) @@ -1076,6 +1077,7 @@ pub mod x64 { stack: wasm_stack, locals: wasm_locals, }; + println!("WFS = {:?}", wfs); results.push(wfs); } From 3778352d3900d053aa1693ea1c71459670fdf62d Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 8 Oct 2019 23:01:03 +0800 Subject: [PATCH 029/342] Update a few examples. --- Cargo.lock | 4 ++++ Cargo.toml | 3 ++- examples/hello_world/Cargo.toml | 9 +++++++++ examples/hello_world/src/main.rs | 7 +++++++ examples/iterative_hash/src/main.rs | 2 +- 5 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 examples/hello_world/Cargo.toml create mode 100644 examples/hello_world/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 5f15df164e9..b1b20a08f87 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -610,6 +610,10 @@ dependencies = [ "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hello_world" +version = "0.1.0" + [[package]] name = "hex" version = "0.3.2" diff --git a/Cargo.toml b/Cargo.toml index bbd596087c7..dd5b48b6a91 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,7 +58,8 @@ members = [ "lib/wasi-tests", "lib/emscripten-tests", "lib/middleware-common-tests", - "examples/plugin-for-example" + "examples/plugin-for-example", + "examples/hello_world" ] [build-dependencies] diff --git a/examples/hello_world/Cargo.toml b/examples/hello_world/Cargo.toml new file mode 100644 index 00000000000..a71d719ed41 --- /dev/null +++ b/examples/hello_world/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "hello_world" +version = "0.1.0" +authors = ["losfair "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/examples/hello_world/src/main.rs b/examples/hello_world/src/main.rs new file mode 100644 index 00000000000..ca24b9cead6 --- /dev/null +++ b/examples/hello_world/src/main.rs @@ -0,0 +1,7 @@ +fn main() { + for i in 0..8 { + let s = format!("Hello, {}", i); + println!("{}", s); + } + panic!("OK"); +} diff --git a/examples/iterative_hash/src/main.rs b/examples/iterative_hash/src/main.rs index 043bc02a1d4..66ed10405f2 100644 --- a/examples/iterative_hash/src/main.rs +++ b/examples/iterative_hash/src/main.rs @@ -20,7 +20,7 @@ fn main() { let diff = millis - last_millis; if diff >= 100 { record_count += 1; - println!("{}", (i - round_count) as f64 / diff as f64); + println!("{}", ((i - round_count) as u128) * 1000000 / diff ); last_millis = millis; round_count = i; } From 8ee4b7f7b0ce260a9b92ceeda9e705114674234a Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 10 Oct 2019 22:08:52 +0800 Subject: [PATCH 030/342] Replace brk with undefined instruction. --- .../src/translator_aarch64.rs | 110 +++++++++--------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 331d33779fe..107a290e9ef 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -687,7 +687,7 @@ impl Emitter for Assembler { self ; b >ok ; fail: - ; brk 0 + ; .dword 0 ; .dword 0 ; ok: ); } @@ -1089,7 +1089,7 @@ impl Emitter for Assembler { fn emit_popcnt(&mut self, sz: Size, src: Location, dst: Location) { dynasm!( self - ; brk 90 // TODO: Implement + ; .dword 0 ; .dword 90 // TODO: Implement ); } fn emit_movzx(&mut self, sz_src: Size, src: Location, _sz_dst: Size, dst: Location) { @@ -1182,175 +1182,175 @@ impl Emitter for Assembler { // TODO: These instructions are only used in FP opcodes. Implement later. fn emit_btc_gpr_imm8_32(&mut self, src: u8, dst: GPR) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_btc_gpr_imm8_64(&mut self, src: u8, dst: GPR) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_cmovae_gpr_32(&mut self, src: GPR, dst: GPR) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_cmovae_gpr_64(&mut self, src: GPR, dst: GPR) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vaddss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vaddsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vsubss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vsubsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vmulss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vmulsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vdivss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vdivsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vmaxss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vmaxsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vminss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vminsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vcmpeqss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vcmpeqsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vcmpneqss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vcmpneqsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vcmpltss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vcmpltsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vcmpless(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vcmplesd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vcmpgtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vcmpgtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vcmpgess(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vcmpgesd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vsqrtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vsqrtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vroundss_nearest(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vroundss_floor(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vroundss_ceil(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vroundss_trunc(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vroundsd_nearest(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vroundsd_floor(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vroundsd_ceil(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vroundsd_trunc(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vcvtss2sd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vcvtsd2ss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_ucomiss(&mut self, src: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_ucomisd(&mut self, src: XMMOrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_cvttss2si_32(&mut self, src: XMMOrMemory, dst: GPR) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_cvttss2si_64(&mut self, src: XMMOrMemory, dst: GPR) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_cvttsd2si_32(&mut self, src: XMMOrMemory, dst: GPR) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_cvttsd2si_64(&mut self, src: XMMOrMemory, dst: GPR) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vcvtsi2ss_32(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vcvtsi2ss_64(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vcvtsi2sd_32(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_vcvtsi2sd_64(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_test_gpr_64(&mut self, reg: GPR) { - dynasm!(self ; brk 29) + dynasm!(self ; .dword 0 ; .dword 29) } fn emit_ud2(&mut self) { - dynasm!(self ; brk 2) + dynasm!(self ; .dword 0 ; .dword 2) } fn emit_ret(&mut self) { dynasm!(self @@ -1418,7 +1418,7 @@ impl Emitter for Assembler { } fn emit_bkpt(&mut self) { - dynasm!(self ; brk 1) + dynasm!(self ; .dword 0 ; .dword 1) } fn emit_homomorphic_host_redirection(&mut self, target: GPR) { From 2e1fb7abca7e1bdf0effd89bd8c4a6a387c58859 Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 11 Oct 2019 21:04:09 +0800 Subject: [PATCH 031/342] Update call_trace middleware to include a counter. --- lib/middleware-common/src/call_trace.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/middleware-common/src/call_trace.rs b/lib/middleware-common/src/call_trace.rs index 04a763abcdf..6430cc03897 100644 --- a/lib/middleware-common/src/call_trace.rs +++ b/lib/middleware-common/src/call_trace.rs @@ -2,8 +2,19 @@ use wasmer_runtime_core::{ codegen::{Event, EventSink, FunctionMiddleware, InternalEvent}, module::ModuleInfo, }; +use std::sync::{Arc, atomic::{Ordering, AtomicU32}}; -pub struct CallTrace; +pub struct CallTrace { + counter: Arc, +} + +impl CallTrace { + pub fn new() -> CallTrace { + CallTrace { + counter: Arc::new(AtomicU32::new(0)), + } + } +} impl FunctionMiddleware for CallTrace { type Error = String; @@ -13,10 +24,13 @@ impl FunctionMiddleware for CallTrace { _module_info: &ModuleInfo, sink: &mut EventSink<'a, 'b>, ) -> Result<(), Self::Error> { + let counter = self.counter.clone(); + match op { Event::Internal(InternalEvent::FunctionBegin(id)) => sink.push(Event::Internal( InternalEvent::Breakpoint(Box::new(move |_| { - eprintln!("func ({})", id); + let idx = counter.fetch_add(1, Ordering::SeqCst); + eprintln!("[{}] func ({})", idx, id); Ok(()) })), )), From db59127f7181497d7ab87d069a556d524b46e824 Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 11 Oct 2019 21:04:53 +0800 Subject: [PATCH 032/342] Inline breakpoint support in core. --- lib/runtime-core/src/backend.rs | 72 +++++++++++++++++++++++++ lib/runtime-core/src/fault.rs | 96 +++++++++++++++++++++++++-------- lib/runtime-core/src/state.rs | 2 + 3 files changed, 148 insertions(+), 22 deletions(-) diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs index 0a062ba5f5c..9491c23776d 100644 --- a/lib/runtime-core/src/backend.rs +++ b/lib/runtime-core/src/backend.rs @@ -70,6 +70,78 @@ impl std::str::FromStr for Backend { } } +#[derive(Copy, Clone, Debug)] +pub enum Architecture { + X64, + Aarch64, +} + +#[repr(u8)] +#[derive(Copy, Clone, Debug)] +pub enum InlineBreakpointType { + Trace, + Middleware, + Unknown, +} + +#[derive(Clone, Debug)] +pub struct InlineBreakpoint { + pub size: usize, + pub ty: InlineBreakpointType, +} + +pub fn get_inline_breakpoint_size(arch: Architecture, backend: Backend) -> Option { + match (arch, backend) { + (Architecture::X64, Backend::Singlepass) => Some(7), + (Architecture::Aarch64, Backend::Singlepass) => Some(12), + _ => None + } +} + +pub fn read_inline_breakpoint(arch: Architecture, backend: Backend, code: &[u8]) -> Option { + match arch { + Architecture::X64 => match backend { + Backend::Singlepass => { + if code.len() < 7 { + None + } else if &code[..6] == &[0x0f, 0x0b, 0x0f, 0xb9, 0xcd, 0xff] { + // ud2 ud (int 0xff) code + Some(InlineBreakpoint { + size: 7, + ty: match code[6] { + 0 => InlineBreakpointType::Trace, + 1 => InlineBreakpointType::Middleware, + _ => InlineBreakpointType::Unknown, + }, + }) + } else { + None + } + } + _ => None + }, + Architecture::Aarch64 => match backend { + Backend::Singlepass => { + if code.len() < 12 { + None + } else if &code[..8] == &[0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff] { + Some(InlineBreakpoint { + size: 12, + ty: match code[8] { + 0 => InlineBreakpointType::Trace, + 1 => InlineBreakpointType::Middleware, + _ => InlineBreakpointType::Unknown, + } + }) + } else { + None + } + }, + _ => None, + } + } +} + #[cfg(test)] mod backend_test { use super::*; diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index 68148bb1c52..23d17de16a6 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -244,9 +244,59 @@ extern "C" fn signal_trap_handler( siginfo: *mut siginfo_t, ucontext: *mut c_void, ) { + use crate::backend::{Architecture, InlineBreakpointType, get_inline_breakpoint_size, read_inline_breakpoint}; + + #[cfg(target_arch = "x86_64")] + static ARCH: Architecture = Architecture::X64; + + #[cfg(target_arch = "aarch64")] + static ARCH: Architecture = Architecture::Aarch64; + unsafe { let fault = get_fault_info(siginfo as _, ucontext); - println!("Fault: {:?}", fault); + let early_return = CURRENT_CODE_VERSIONS.with(|versions| { + let versions = versions.borrow(); + for v in versions.iter() { + let magic_size = if let Some(x) = get_inline_breakpoint_size(ARCH, v.backend) { + x + } else { + continue + }; + let ip = fault.ip.get(); + let end = v.base + v.msm.total_size; + if ip >= v.base && ip < end && ip + magic_size <= end { + if let Some(ib) = read_inline_breakpoint(ARCH, v.backend, unsafe { + std::slice::from_raw_parts(ip as *const u8, magic_size) + }) { + fault.ip.set(ip + magic_size); + + match ib.ty { + InlineBreakpointType::Trace => {}, + InlineBreakpointType::Middleware => { + let out: Option>> = with_breakpoint_map(|bkpt_map| { + bkpt_map.and_then(|x| x.get(&ip)).map(|x| { + x(BreakpointInfo { + fault: Some(&fault), + }) + }) + }); + if let Some(Ok(())) = out { + } else { + println!("Failed calling middleware: {:?}", out); + } + } + _ => println!("Unknown breakpoint type: {:?}", ib.ty) + } + return true; + } + break; + } + } + false + }); + if early_return { + return; + } let mut unwind_result: Box = Box::new(()); @@ -259,7 +309,7 @@ extern "C" fn signal_trap_handler( Ok(SIGTRAP) => { // breakpoint let out: Option>> = with_breakpoint_map(|bkpt_map| { - bkpt_map.and_then(|x| x.get(&(fault.ip as usize))).map(|x| { + bkpt_map.and_then(|x| x.get(&(fault.ip.get()))).map(|x| { x(BreakpointInfo { fault: Some(&fault), }) @@ -293,12 +343,11 @@ extern "C" fn signal_trap_handler( let es_image = CURRENT_CODE_VERSIONS.with(|versions| { let versions = versions.borrow(); - println!("V = {}", versions.len()); read_stack( || versions.iter(), rsp as usize as *const u64, fault.known_registers, - Some(fault.ip as usize as u64), + Some(fault.ip.get() as u64), ) }); @@ -307,7 +356,6 @@ extern "C" fn signal_trap_handler( unwind_result = Box::new(image); } else { use colored::*; - println!("F = {}", es_image.frames.len()); if es_image.frames.len() > 0 { eprintln!( "\n{}", @@ -374,12 +422,12 @@ unsafe fn install_sighandler() { #[derive(Debug, Clone)] pub struct FaultInfo { pub faulting_addr: *const c_void, - pub ip: *const c_void, + pub ip: &'static Cell, pub known_registers: [Option; 24], } #[cfg(all(target_os = "linux", target_arch = "aarch64"))] -pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> FaultInfo { +pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> FaultInfo { #[allow(dead_code)] #[repr(packed)] struct sigcontext { @@ -411,7 +459,7 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> let siginfo = siginfo as *const siginfo_t; let si_addr = (*siginfo).si_addr; - let ucontext = ucontext as *const ucontext; + let ucontext = ucontext as *mut ucontext; let gregs = &(*ucontext).uc_mcontext.regs; let mut known_registers: [Option; 24] = [None; 24]; @@ -436,13 +484,13 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> FaultInfo { faulting_addr: si_addr as usize as _, - ip: (*ucontext).uc_mcontext.pc as _, + ip: std::mem::transmute::<&mut u64, &'static Cell>(&mut (*ucontext).uc_mcontext.pc), known_registers, } } #[cfg(all(target_os = "linux", target_arch = "x86_64"))] -pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> FaultInfo { +pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> FaultInfo { use libc::{ _libc_xmmreg, ucontext_t, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15, REG_R8, REG_R9, REG_RAX, REG_RBP, REG_RBX, REG_RCX, REG_RDI, REG_RDX, REG_RIP, REG_RSI, REG_RSP, @@ -465,9 +513,8 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> let siginfo = siginfo as *const siginfo_t; let si_addr = (*siginfo).si_addr; - let ucontext = ucontext as *const ucontext_t; - let gregs = &(*ucontext).uc_mcontext.gregs; - let fpregs = &*(*ucontext).uc_mcontext.fpregs; + let ucontext = ucontext as *mut ucontext_t; + let gregs = &mut (*ucontext).uc_mcontext.gregs; let mut known_registers: [Option; 24] = [None; 24]; known_registers[X64Register::GPR(GPR::R15).to_index().0] = Some(gregs[REG_R15 as usize] as _); @@ -488,18 +535,23 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> known_registers[X64Register::GPR(GPR::RBP).to_index().0] = Some(gregs[REG_RBP as usize] as _); known_registers[X64Register::GPR(GPR::RSP).to_index().0] = Some(gregs[REG_RSP as usize] as _); - known_registers[X64Register::XMM(XMM::XMM0).to_index().0] = Some(read_xmm(&fpregs._xmm[0])); - known_registers[X64Register::XMM(XMM::XMM1).to_index().0] = Some(read_xmm(&fpregs._xmm[1])); - known_registers[X64Register::XMM(XMM::XMM2).to_index().0] = Some(read_xmm(&fpregs._xmm[2])); - known_registers[X64Register::XMM(XMM::XMM3).to_index().0] = Some(read_xmm(&fpregs._xmm[3])); - known_registers[X64Register::XMM(XMM::XMM4).to_index().0] = Some(read_xmm(&fpregs._xmm[4])); - 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])); + // WSL bug + if !(*ucontext).uc_mcontext.fpregs.is_null() { + let fpregs = &*(*ucontext).uc_mcontext.fpregs; + + known_registers[X64Register::XMM(XMM::XMM0).to_index().0] = Some(read_xmm(&fpregs._xmm[0])); + known_registers[X64Register::XMM(XMM::XMM1).to_index().0] = Some(read_xmm(&fpregs._xmm[1])); + known_registers[X64Register::XMM(XMM::XMM2).to_index().0] = Some(read_xmm(&fpregs._xmm[2])); + known_registers[X64Register::XMM(XMM::XMM3).to_index().0] = Some(read_xmm(&fpregs._xmm[3])); + known_registers[X64Register::XMM(XMM::XMM4).to_index().0] = Some(read_xmm(&fpregs._xmm[4])); + 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])); + } FaultInfo { faulting_addr: si_addr as usize as _, - ip: gregs[REG_RIP as usize] as _, + ip: std::mem::transmute::<&mut i64, &'static Cell>(&mut gregs[REG_RIP as usize]), known_registers, } } diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 1896c5c9e2a..82f34eaed85 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -1,5 +1,6 @@ use std::collections::BTreeMap; use std::ops::Bound::{Included, Unbounded}; +use crate::backend::Backend; #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct RegisterIndex(pub usize); @@ -111,6 +112,7 @@ pub struct CodeVersion { pub baseline: bool, pub msm: ModuleStateMap, pub base: usize, + pub backend: Backend, } impl ModuleStateMap { From 94f97109ff12abd5c3362257ef70e535326dc2a1 Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 11 Oct 2019 21:05:17 +0800 Subject: [PATCH 033/342] Include backend metadata in tiering module. --- lib/runtime-core/src/tiering.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/runtime-core/src/tiering.rs b/lib/runtime-core/src/tiering.rs index 21a9ea2d377..2eea60de773 100644 --- a/lib/runtime-core/src/tiering.rs +++ b/lib/runtime-core/src/tiering.rs @@ -1,4 +1,4 @@ -use crate::backend::{Compiler, CompilerConfig}; +use crate::backend::{Backend, Compiler, CompilerConfig}; use crate::compile_with_config; use crate::fault::{ catch_unsafe_unwind, ensure_sighandler, pop_code_version, push_code_version, with_ctx, @@ -36,6 +36,7 @@ struct OptimizationState { } struct OptimizationOutcome { + backend_id: Backend, module: Module, } @@ -46,6 +47,7 @@ unsafe impl Sync for CtxWrapper {} unsafe fn do_optimize( binary: &[u8], + backend_id: Backend, compiler: Box, ctx: &Mutex, state: &OptimizationState, @@ -65,7 +67,7 @@ unsafe fn do_optimize( let ctx_inner = ctx.lock().unwrap(); if !ctx_inner.0.is_null() { - *state.outcome.lock().unwrap() = Some(OptimizationOutcome { module }); + *state.outcome.lock().unwrap() = Some(OptimizationOutcome { backend_id, module }); set_wasm_interrupt_on_ctx(ctx_inner.0); } } @@ -77,7 +79,8 @@ pub unsafe fn run_tiering ShellExitOperation>( import_object: &ImportObject, start_raw: extern "C" fn(&mut Ctx), baseline: &mut Instance, - optimized_backends: Vec Box + Send>>, + baseline_backend: Backend, + optimized_backends: Vec<(Backend, Box Box + Send>)>, interactive_shell: F, ) -> Result<(), String> { ensure_sighandler(); @@ -99,9 +102,9 @@ pub unsafe fn run_tiering ShellExitOperation>( let ctx_box = ctx_box.clone(); let opt_state = opt_state.clone(); ::std::thread::spawn(move || { - for backend in optimized_backends { + for (backend_id, backend) in optimized_backends { if !ctx_box.lock().unwrap().0.is_null() { - do_optimize(&wasm_binary, backend(), &ctx_box, &opt_state); + do_optimize(&wasm_binary, backend_id, backend(), &ctx_box, &opt_state); } } }); @@ -117,6 +120,7 @@ pub unsafe fn run_tiering ShellExitOperation>( .get_module_state_map() .unwrap(), base: baseline.module.runnable_module.get_code().unwrap().as_ptr() as usize, + backend: baseline_backend, }); let n_versions: Cell = Cell::new(1); @@ -127,7 +131,7 @@ pub unsafe fn run_tiering ShellExitOperation>( })); loop { - let new_optimized: Option<&mut Instance> = { + let new_optimized: Option<(Backend, &mut Instance)> = { let mut outcome = opt_state.outcome.lock().unwrap(); if let Some(x) = outcome.take() { let instance = x @@ -136,12 +140,12 @@ pub unsafe fn run_tiering ShellExitOperation>( .map_err(|e| format!("Can't instantiate module: {:?}", e))?; // Keep the optimized code alive. optimized_instances.push(instance); - optimized_instances.last_mut() + optimized_instances.last_mut().map(|y| (x.backend_id, y)) } else { None } }; - if let Some(optimized) = new_optimized { + if let Some((backend_id, optimized)) = new_optimized { let base = module_info.imported_functions.len(); let code_ptr = optimized .module @@ -178,6 +182,7 @@ pub unsafe fn run_tiering ShellExitOperation>( .get_code() .unwrap() .as_ptr() as usize, + backend: backend_id, }); n_versions.set(n_versions.get() + 1); From 36f95fc6602f2cc999cf470f19dd750beb336219 Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 11 Oct 2019 21:05:42 +0800 Subject: [PATCH 034/342] Support emitting inline breakpoints in singlepass. --- lib/singlepass-backend/src/codegen_x64.rs | 3 ++- lib/singlepass-backend/src/emitter_x64.rs | 11 +++++++++++ lib/singlepass-backend/src/translator_aarch64.rs | 9 +++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 1b081717a2a..08320d1494a 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -1904,11 +1904,12 @@ impl FunctionCodeGenerator for X64FunctionCode { Event::Internal(x) => { match x { InternalEvent::Breakpoint(callback) => { - a.emit_bkpt(); + use wasmer_runtime_core::backend::InlineBreakpointType; self.breakpoints .as_mut() .unwrap() .insert(a.get_offset(), callback); + a.emit_inline_breakpoint(InlineBreakpointType::Middleware); } InternalEvent::FunctionBegin(_) | InternalEvent::FunctionEnd => {} InternalEvent::GetInternal(idx) => { diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index 41134473a76..d16c872335d 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -1,5 +1,6 @@ use dynasmrt::{x64::Assembler, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi}; pub use wasmer_runtime_core::state::x64_decl::{GPR, XMM}; +use wasmer_runtime_core::backend::{InlineBreakpointType}; #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum Location { @@ -171,6 +172,7 @@ pub trait Emitter { fn emit_bkpt(&mut self); fn emit_homomorphic_host_redirection(&mut self, target: GPR); + fn emit_inline_breakpoint(&mut self, ty: InlineBreakpointType); } fn _dummy(a: &mut Assembler) { @@ -951,4 +953,13 @@ impl Emitter for Assembler { fn emit_homomorphic_host_redirection(&mut self, target: GPR) { self.emit_jmp_location(Location::GPR(target)); } + + fn emit_inline_breakpoint(&mut self, ty: InlineBreakpointType) { + dynasm!(self + ; ud2 + ; .byte 0x0f ; .byte (0xb9u8 as i8) // ud + ; int -1 + ; .byte (ty as u8 as i8) + ); + } } diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 107a290e9ef..3ae27ddd86c 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -3,6 +3,7 @@ use crate::codegen_x64::*; use crate::emitter_x64::*; use dynasmrt::{aarch64::Assembler, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi}; +use wasmer_runtime_core::backend::{InlineBreakpointType}; #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] pub struct AX(pub u32); @@ -1474,6 +1475,14 @@ impl Emitter for Assembler { ; br x_tmp1 ); } + + fn emit_inline_breakpoint(&mut self, ty: InlineBreakpointType) { + dynasm!(self + ; .dword 0 + ; .dword -1 + ; .dword (ty as u8 as i32) + ); + } } fn emit_clz_variant(assembler: &mut Assembler, sz: Size, src: &Location, dst: &Location, reversed: bool) { From ad3faa0ba061fd8d4f839d075d4df0ec2d4d328a Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 11 Oct 2019 21:05:59 +0800 Subject: [PATCH 035/342] Add CallTrace CLI option. --- src/bin/wasmer.rs | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index f1e20328b30..16d048d979b 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -36,8 +36,6 @@ use wasmer_runtime_core::{ debug, loader::{Instance as LoadedInstance, LocalLoader}, }; -#[cfg(feature = "backend-singlepass")] -use wasmer_singlepass_backend::SinglePassCompiler; #[cfg(feature = "wasi")] use wasmer_wasi; @@ -81,7 +79,7 @@ enum CLIOptions { SelfUpdate, } -#[derive(Debug, StructOpt)] +#[derive(Debug, StructOpt, Clone)] struct PrestandardFeatures { /// Enable support for the SIMD proposal. #[structopt(long = "enable-simd")] @@ -113,7 +111,7 @@ pub struct LLVMCLIOptions { obj_file: Option, } -#[derive(Debug, StructOpt)] +#[derive(Debug, StructOpt, Clone)] struct Run { // Disable the cache #[structopt(long = "disable-cache")] @@ -177,6 +175,10 @@ struct Run { #[structopt(long = "no-track-state")] no_track_state: bool, + // Enable the CallTrace middleware. + #[structopt(long = "call-trace")] + call_trace: 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 /// help commands and error messages of the running wasm program @@ -397,7 +399,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { .map_err(|e| format!("Can't convert from wast to wasm: {:?}", e))?; } - let compiler: Box = match get_compiler_by_backend(options.backend) { + let compiler: Box = match get_compiler_by_backend(options.backend, options) { Some(x) => x, None => return Err("the requested backend is not enabled".into()), }; @@ -615,11 +617,13 @@ fn execute_wasm(options: &Run) -> Result<(), String> { &import_object, start_raw, &mut instance, + options.backend, options .optimized_backends .iter() - .map(|&backend| -> Box Box + Send> { - Box::new(move || get_compiler_by_backend(backend).unwrap()) + .map(|&backend| -> (Backend, Box Box + Send>) { + let options = options.clone(); + (backend, Box::new(move || get_compiler_by_backend(backend, &options).unwrap())) }) .collect(), interactive_shell, @@ -639,6 +643,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { baseline: true, msm: instance.module.runnable_module.get_module_state_map().unwrap(), base: instance.module.runnable_module.get_code().unwrap().as_ptr() as usize, + backend: options.backend, }); let result = start.call(); pop_code_version().unwrap(); @@ -809,10 +814,27 @@ fn validate(validate: Validate) { } } -fn get_compiler_by_backend(backend: Backend) -> Option> { +fn get_compiler_by_backend(backend: Backend, opts: &Run) -> Option> { + use wasmer_runtime_core::codegen::{MiddlewareChain}; + let opts = opts.clone(); + let middlewares_gen = move || { + let mut middlewares = MiddlewareChain::new(); + if opts.call_trace { + use wasmer_middleware_common::call_trace::CallTrace; + middlewares.push(CallTrace::new()); + } + middlewares + }; + Some(match backend { #[cfg(feature = "backend-singlepass")] - Backend::Singlepass => Box::new(SinglePassCompiler::new()), + Backend::Singlepass => { + use wasmer_singlepass_backend::ModuleCodeGenerator as SinglePassMCG; + use wasmer_runtime_core::codegen::{StreamingCompiler}; + + let c: StreamingCompiler = StreamingCompiler::new(middlewares_gen); + Box::new(c) + } #[cfg(not(feature = "backend-singlepass"))] Backend::Singlepass => return None, Backend::Cranelift => Box::new(CraneliftCompiler::new()), From c18bdd52ccd1b0d46db2fd01fd8af7f7bdf7d8bf Mon Sep 17 00:00:00 2001 From: losfair Date: Sun, 13 Oct 2019 20:02:28 +0800 Subject: [PATCH 036/342] Fix inline breakpoints on macOS. --- lib/runtime-core/src/fault.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index 23d17de16a6..1a50b3faae3 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -265,9 +265,7 @@ extern "C" fn signal_trap_handler( let ip = fault.ip.get(); let end = v.base + v.msm.total_size; if ip >= v.base && ip < end && ip + magic_size <= end { - if let Some(ib) = read_inline_breakpoint(ARCH, v.backend, unsafe { - std::slice::from_raw_parts(ip as *const u8, magic_size) - }) { + if let Some(ib) = read_inline_breakpoint(ARCH, v.backend, std::slice::from_raw_parts(ip as *const u8, magic_size)) { fault.ip.set(ip + magic_size); match ib.ty { @@ -557,7 +555,7 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> F } #[cfg(all(target_os = "macos", target_arch = "x86_64"))] -pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> FaultInfo { +pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> FaultInfo { #[allow(dead_code)] #[repr(C)] struct ucontext_t { @@ -566,7 +564,7 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> uc_stack: libc::stack_t, uc_link: *const ucontext_t, uc_mcsize: u64, - uc_mcontext: *const mcontext_t, + uc_mcontext: *mut mcontext_t, } #[repr(C)] struct exception_state { @@ -615,8 +613,8 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> let siginfo = siginfo as *const siginfo_t; let si_addr = (*siginfo).si_addr; - let ucontext = ucontext as *const ucontext_t; - let ss = &(*(*ucontext).uc_mcontext).ss; + let ucontext = ucontext as *mut ucontext_t; + let ss = &mut (*(*ucontext).uc_mcontext).ss; let fs = &(*(*ucontext).uc_mcontext).fs; let mut known_registers: [Option; 24] = [None; 24]; @@ -650,7 +648,7 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> FaultInfo { faulting_addr: si_addr, - ip: ss.rip as _, + ip: std::mem::transmute::<&mut u64, &'static Cell>(&mut ss.rip), known_registers, } } From 5499a69ddc2780331044e1913ab8c35bb66ceb64 Mon Sep 17 00:00:00 2001 From: losfair Date: Sun, 13 Oct 2019 20:02:47 +0800 Subject: [PATCH 037/342] Run cargo fmt on everything. --- lib/middleware-common/src/call_trace.rs | 5 +- lib/runtime-core/src/backend.rs | 16 +- lib/runtime-core/src/fault.rs | 31 ++- lib/runtime-core/src/state.rs | 2 +- lib/singlepass-backend/src/emitter_x64.rs | 2 +- .../src/translator_aarch64.rs | 215 +++++++++--------- src/bin/wasmer.rs | 34 ++- 7 files changed, 166 insertions(+), 139 deletions(-) diff --git a/lib/middleware-common/src/call_trace.rs b/lib/middleware-common/src/call_trace.rs index 6430cc03897..5cb77534c56 100644 --- a/lib/middleware-common/src/call_trace.rs +++ b/lib/middleware-common/src/call_trace.rs @@ -1,8 +1,11 @@ +use std::sync::{ + atomic::{AtomicU32, Ordering}, + Arc, +}; use wasmer_runtime_core::{ codegen::{Event, EventSink, FunctionMiddleware, InternalEvent}, module::ModuleInfo, }; -use std::sync::{Arc, atomic::{Ordering, AtomicU32}}; pub struct CallTrace { counter: Arc, diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs index 9491c23776d..ae439969e5c 100644 --- a/lib/runtime-core/src/backend.rs +++ b/lib/runtime-core/src/backend.rs @@ -94,11 +94,15 @@ pub fn get_inline_breakpoint_size(arch: Architecture, backend: Backend) -> Optio match (arch, backend) { (Architecture::X64, Backend::Singlepass) => Some(7), (Architecture::Aarch64, Backend::Singlepass) => Some(12), - _ => None + _ => None, } } -pub fn read_inline_breakpoint(arch: Architecture, backend: Backend, code: &[u8]) -> Option { +pub fn read_inline_breakpoint( + arch: Architecture, + backend: Backend, + code: &[u8], +) -> Option { match arch { Architecture::X64 => match backend { Backend::Singlepass => { @@ -118,7 +122,7 @@ pub fn read_inline_breakpoint(arch: Architecture, backend: Backend, code: &[u8]) None } } - _ => None + _ => None, }, Architecture::Aarch64 => match backend { Backend::Singlepass => { @@ -131,14 +135,14 @@ pub fn read_inline_breakpoint(arch: Architecture, backend: Backend, code: &[u8]) 0 => InlineBreakpointType::Trace, 1 => InlineBreakpointType::Middleware, _ => InlineBreakpointType::Unknown, - } + }, }) } else { None } - }, + } _ => None, - } + }, } } diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index 1a50b3faae3..51d00d52e25 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -244,7 +244,9 @@ extern "C" fn signal_trap_handler( siginfo: *mut siginfo_t, ucontext: *mut c_void, ) { - use crate::backend::{Architecture, InlineBreakpointType, get_inline_breakpoint_size, read_inline_breakpoint}; + use crate::backend::{ + get_inline_breakpoint_size, read_inline_breakpoint, Architecture, InlineBreakpointType, + }; #[cfg(target_arch = "x86_64")] static ARCH: Architecture = Architecture::X64; @@ -260,30 +262,35 @@ extern "C" fn signal_trap_handler( let magic_size = if let Some(x) = get_inline_breakpoint_size(ARCH, v.backend) { x } else { - continue + continue; }; let ip = fault.ip.get(); let end = v.base + v.msm.total_size; if ip >= v.base && ip < end && ip + magic_size <= end { - if let Some(ib) = read_inline_breakpoint(ARCH, v.backend, std::slice::from_raw_parts(ip as *const u8, magic_size)) { + if let Some(ib) = read_inline_breakpoint( + ARCH, + v.backend, + std::slice::from_raw_parts(ip as *const u8, magic_size), + ) { fault.ip.set(ip + magic_size); - + match ib.ty { - InlineBreakpointType::Trace => {}, + InlineBreakpointType::Trace => {} InlineBreakpointType::Middleware => { - let out: Option>> = with_breakpoint_map(|bkpt_map| { - bkpt_map.and_then(|x| x.get(&ip)).map(|x| { - x(BreakpointInfo { - fault: Some(&fault), + let out: Option>> = + with_breakpoint_map(|bkpt_map| { + bkpt_map.and_then(|x| x.get(&ip)).map(|x| { + x(BreakpointInfo { + fault: Some(&fault), + }) }) - }) - }); + }); if let Some(Ok(())) = out { } else { println!("Failed calling middleware: {:?}", out); } } - _ => println!("Unknown breakpoint type: {:?}", ib.ty) + _ => println!("Unknown breakpoint type: {:?}", ib.ty), } return true; } diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 82f34eaed85..e31e55bb476 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -1,6 +1,6 @@ +use crate::backend::Backend; use std::collections::BTreeMap; use std::ops::Bound::{Included, Unbounded}; -use crate::backend::Backend; #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct RegisterIndex(pub usize); diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index d16c872335d..1d0127cf7b5 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -1,6 +1,6 @@ use dynasmrt::{x64::Assembler, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi}; +use wasmer_runtime_core::backend::InlineBreakpointType; pub use wasmer_runtime_core::state::x64_decl::{GPR, XMM}; -use wasmer_runtime_core::backend::{InlineBreakpointType}; #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum Location { diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 3ae27ddd86c..55649db4993 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -3,7 +3,7 @@ use crate::codegen_x64::*; use crate::emitter_x64::*; use dynasmrt::{aarch64::Assembler, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi}; -use wasmer_runtime_core::backend::{InlineBreakpointType}; +use wasmer_runtime_core::backend::InlineBreakpointType; #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] pub struct AX(pub u32); @@ -558,7 +558,7 @@ impl Emitter for Assembler { } dynasm!(self ; str D(map_xmm(src).v()), [x_tmp3] ); } - _ => panic!("NOT IMPL: {:?} {:?} {:?}", sz, src, dst) + _ => panic!("NOT IMPL: {:?} {:?} {:?}", sz, src, dst), } } @@ -844,7 +844,7 @@ impl Emitter for Assembler { ; ldr w_tmp1, [x_tmp3] ; cmp w_tmp1, W(map_gpr(left).x()) ) - }, + } (Size::S64, Location::GPR(left), Location::Memory(base, disp)) => { if disp >= 0 { dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); @@ -856,7 +856,7 @@ impl Emitter for Assembler { ; ldr x_tmp1, [x_tmp3] ; cmp x_tmp1, X(map_gpr(left).x()) ) - }, + } (Size::S32, Location::Memory(base, disp), Location::GPR(right)) => { if disp >= 0 { dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); @@ -868,7 +868,7 @@ impl Emitter for Assembler { ; ldr w_tmp1, [x_tmp3] ; cmp W(map_gpr(right).x()), w_tmp1 ) - }, + } (Size::S64, Location::Memory(base, disp), Location::GPR(right)) => { if disp >= 0 { dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); @@ -880,7 +880,7 @@ impl Emitter for Assembler { ; ldr x_tmp1, [x_tmp3] ; cmp X(map_gpr(right).x()), x_tmp1 ) - }, + } _ => unreachable!(), } } @@ -927,7 +927,7 @@ impl Emitter for Assembler { ; ldr w_tmp1, [x_tmp3] ) } - _ => unreachable!() + _ => unreachable!(), } dynasm!( self @@ -953,7 +953,7 @@ impl Emitter for Assembler { ; ldr x_tmp1, [x_tmp3] ) } - _ => unreachable!() + _ => unreachable!(), } dynasm!( self @@ -962,7 +962,7 @@ impl Emitter for Assembler { ; msub X(map_gpr(GPR::RDX).x()), X(map_gpr(GPR::RAX).x()), x_tmp1, x_tmp2 ) } - _ => unreachable!() + _ => unreachable!(), } } fn emit_idiv(&mut self, sz: Size, divisor: Location) { @@ -984,7 +984,7 @@ impl Emitter for Assembler { ; ldr w_tmp1, [x_tmp3] ) } - _ => unreachable!() + _ => unreachable!(), } dynasm!( self @@ -1010,7 +1010,7 @@ impl Emitter for Assembler { ; ldr x_tmp1, [x_tmp3] ) } - _ => unreachable!() + _ => unreachable!(), } dynasm!( self @@ -1019,7 +1019,7 @@ impl Emitter for Assembler { ; msub X(map_gpr(GPR::RDX).x()), X(map_gpr(GPR::RAX).x()), x_tmp1, x_tmp2 ) } - _ => unreachable!() + _ => unreachable!(), } } fn emit_shl(&mut self, sz: Size, src: Location, dst: Location) { @@ -1034,43 +1034,42 @@ impl Emitter for Assembler { fn emit_rol(&mut self, sz: Size, src: Location, dst: Location) { // TODO: We are changing content of `src` (possibly RCX) here. Will this break any assumptions? match sz { - Size::S32 => { - match src { - Location::Imm8(x) => { - assert!(x < 32); - binop_shift!(ror, self, sz, Location::Imm8(32 - x), dst, { unreachable!("rol") }); - } - Location::GPR(GPR::RCX) => { - dynasm!( - self - ; mov w_tmp1, 32 - ; sub W(map_gpr(GPR::RCX).x()), w_tmp1, W(map_gpr(GPR::RCX).x()) - ); - binop_shift!(ror, self, sz, src, dst, { unreachable!("rol") }); - } - _ => unreachable!() + Size::S32 => match src { + Location::Imm8(x) => { + assert!(x < 32); + binop_shift!(ror, self, sz, Location::Imm8(32 - x), dst, { + unreachable!("rol") + }); } - } - Size::S64 => { - match src { - Location::Imm8(x) => { - assert!(x < 64); - binop_shift!(ror, self, sz, Location::Imm8(64 - x), dst, { unreachable!("rol") }); - } - Location::GPR(GPR::RCX) => { - dynasm!( - self - ; mov x_tmp1, 64 - ; sub X(map_gpr(GPR::RCX).x()), x_tmp1, X(map_gpr(GPR::RCX).x()) - ); - binop_shift!(ror, self, sz, src, dst, { unreachable!("rol") }); - } - _ => unreachable!() + Location::GPR(GPR::RCX) => { + dynasm!( + self + ; mov w_tmp1, 32 + ; sub W(map_gpr(GPR::RCX).x()), w_tmp1, W(map_gpr(GPR::RCX).x()) + ); + binop_shift!(ror, self, sz, src, dst, { unreachable!("rol") }); } - } - _ => unreachable!() + _ => unreachable!(), + }, + Size::S64 => match src { + Location::Imm8(x) => { + assert!(x < 64); + binop_shift!(ror, self, sz, Location::Imm8(64 - x), dst, { + unreachable!("rol") + }); + } + Location::GPR(GPR::RCX) => { + dynasm!( + self + ; mov x_tmp1, 64 + ; sub X(map_gpr(GPR::RCX).x()), x_tmp1, X(map_gpr(GPR::RCX).x()) + ); + binop_shift!(ror, self, sz, src, dst, { unreachable!("rol") }); + } + _ => unreachable!(), + }, + _ => unreachable!(), } - } fn emit_ror(&mut self, sz: Size, src: Location, dst: Location) { binop_shift!(ror, self, sz, src, dst, { unreachable!("ror") }); @@ -1485,76 +1484,78 @@ impl Emitter for Assembler { } } -fn emit_clz_variant(assembler: &mut Assembler, sz: Size, src: &Location, dst: &Location, reversed: bool) { +fn emit_clz_variant( + assembler: &mut Assembler, + sz: Size, + src: &Location, + dst: &Location, + reversed: bool, +) { match sz { - Size::S32 => { - match *src { - Location::GPR(src) => { - dynasm!( - assembler - ; mov w_tmp1, W(map_gpr(src).x()) - ) + Size::S32 => { + match *src { + Location::GPR(src) => dynasm!( + assembler + ; mov w_tmp1, W(map_gpr(src).x()) + ), + Location::Memory(base, disp) => { + if disp >= 0 { + dynasm!(assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(assembler ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); } - Location::Memory(base, disp) => { - if disp >= 0 { - dynasm!(assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); - } else { - dynasm!(assembler ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); - } - dynasm!( - assembler - ; ldr w_tmp1, [x_tmp3] - ) - } - _ => unreachable!() + dynasm!( + assembler + ; ldr w_tmp1, [x_tmp3] + ) } - match *dst { - Location::GPR(dst) => { - if reversed { - dynasm!(assembler ; rbit w_tmp1, w_tmp1); - } - dynasm!( - assembler - ; clz W(map_gpr(dst).x()), w_tmp1 - ); + _ => unreachable!(), + } + match *dst { + Location::GPR(dst) => { + if reversed { + dynasm!(assembler ; rbit w_tmp1, w_tmp1); } - _ => unreachable!() + dynasm!( + assembler + ; clz W(map_gpr(dst).x()), w_tmp1 + ); } + _ => unreachable!(), } - Size::S64 => { - match *src { - Location::GPR(src) => { - dynasm!( - assembler - ; mov x_tmp1, X(map_gpr(src).x()) - ) - } - Location::Memory(base, disp) => { - if disp >= 0 { - dynasm!(assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); - } else { - dynasm!(assembler ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); - } - dynasm!( - assembler - ; ldr x_tmp1, [x_tmp3] - ) + } + Size::S64 => { + match *src { + Location::GPR(src) => dynasm!( + assembler + ; mov x_tmp1, X(map_gpr(src).x()) + ), + Location::Memory(base, disp) => { + if disp >= 0 { + dynasm!(assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + } else { + dynasm!(assembler ; sub x_tmp3, X(map_gpr(base).x()), (-disp) as u32); } - _ => unreachable!() + dynasm!( + assembler + ; ldr x_tmp1, [x_tmp3] + ) } - match *dst { - Location::GPR(dst) => { - if reversed { - dynasm!(assembler ; rbit x_tmp1, x_tmp1) - } - dynasm!( - assembler - ; clz X(map_gpr(dst).x()), x_tmp1 - ); + _ => unreachable!(), + } + match *dst { + Location::GPR(dst) => { + if reversed { + dynasm!(assembler ; rbit x_tmp1, x_tmp1) } - _ => unreachable!() + dynasm!( + assembler + ; clz X(map_gpr(dst).x()), x_tmp1 + ); } + _ => unreachable!(), } - _ => unreachable!() } -} \ No newline at end of file + _ => unreachable!(), + } +} diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 16d048d979b..e54fddd93ce 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -621,10 +621,17 @@ fn execute_wasm(options: &Run) -> Result<(), String> { options .optimized_backends .iter() - .map(|&backend| -> (Backend, Box Box + Send>) { - let options = options.clone(); - (backend, Box::new(move || get_compiler_by_backend(backend, &options).unwrap())) - }) + .map( + |&backend| -> (Backend, Box Box + Send>) { + let options = options.clone(); + ( + backend, + Box::new(move || { + get_compiler_by_backend(backend, &options).unwrap() + }), + ) + }, + ) .collect(), interactive_shell, )? @@ -635,13 +642,17 @@ fn execute_wasm(options: &Run) -> Result<(), String> { { use wasmer_runtime::error::RuntimeError; use wasmer_runtime_core::{ - fault::{push_code_version, pop_code_version}, - state::CodeVersion + fault::{pop_code_version, push_code_version}, + state::CodeVersion, }; push_code_version(CodeVersion { baseline: true, - msm: instance.module.runnable_module.get_module_state_map().unwrap(), + msm: instance + .module + .runnable_module + .get_module_state_map() + .unwrap(), base: instance.module.runnable_module.get_code().unwrap().as_ptr() as usize, backend: options.backend, }); @@ -815,7 +826,7 @@ fn validate(validate: Validate) { } fn get_compiler_by_backend(backend: Backend, opts: &Run) -> Option> { - use wasmer_runtime_core::codegen::{MiddlewareChain}; + use wasmer_runtime_core::codegen::MiddlewareChain; let opts = opts.clone(); let middlewares_gen = move || { let mut middlewares = MiddlewareChain::new(); @@ -825,14 +836,15 @@ fn get_compiler_by_backend(backend: Backend, opts: &Run) -> Option { + use wasmer_runtime_core::codegen::StreamingCompiler; use wasmer_singlepass_backend::ModuleCodeGenerator as SinglePassMCG; - use wasmer_runtime_core::codegen::{StreamingCompiler}; - let c: StreamingCompiler = StreamingCompiler::new(middlewares_gen); + let c: StreamingCompiler = + StreamingCompiler::new(middlewares_gen); Box::new(c) } #[cfg(not(feature = "backend-singlepass"))] From 128b006bf79fefb24e96d251ca6b17edbf75c450 Mon Sep 17 00:00:00 2001 From: losfair Date: Sun, 13 Oct 2019 20:51:03 +0800 Subject: [PATCH 038/342] Add a BlockTrace middleware. --- lib/middleware-common/src/block_trace.rs | 105 +++++++++++++++++++++++ lib/middleware-common/src/lib.rs | 1 + 2 files changed, 106 insertions(+) create mode 100644 lib/middleware-common/src/block_trace.rs diff --git a/lib/middleware-common/src/block_trace.rs b/lib/middleware-common/src/block_trace.rs new file mode 100644 index 00000000000..cb4ae3f21ca --- /dev/null +++ b/lib/middleware-common/src/block_trace.rs @@ -0,0 +1,105 @@ +use wasmer_runtime_core::{ + codegen::{Event, EventSink, FunctionMiddleware, InternalEvent}, + module::ModuleInfo, + wasmparser::Operator, +}; + +pub struct BlockTrace { + func_idx: usize, + evt_idx: usize, +} + +impl BlockTrace { + pub fn new() -> BlockTrace { + BlockTrace { + func_idx: std::usize::MAX, + evt_idx: 0, + } + } +} + +impl FunctionMiddleware for BlockTrace { + type Error = String; + fn feed_event<'a, 'b: 'a>( + &mut self, + op: Event<'a, 'b>, + _module_info: &ModuleInfo, + sink: &mut EventSink<'a, 'b>, + ) -> Result<(), Self::Error> { + match op { + Event::Internal(InternalEvent::FunctionBegin(_)) => { + self.func_idx = self.func_idx.wrapping_add(1); + self.evt_idx = 0; + let func_idx = self.func_idx; + let evt_idx = self.evt_idx; + sink.push(op); + sink.push(Event::Internal(InternalEvent::Breakpoint(Box::new( + move |_| { + eprintln!("[BlockTrace] ({}, {}) -> enter_func", func_idx, evt_idx); + Ok(()) + }, + )))) + } + Event::Wasm(Operator::Call { .. }) => { + let func_idx = self.func_idx; + let evt_idx = self.evt_idx; + sink.push(op); + sink.push(Event::Internal(InternalEvent::Breakpoint(Box::new( + move |_| { + eprintln!("[BlockTrace] ({}, {}) -> leave_call", func_idx, evt_idx); + Ok(()) + }, + )))) + } + Event::Wasm(Operator::Block { .. }) => { + let func_idx = self.func_idx; + let evt_idx = self.evt_idx; + sink.push(op); + sink.push(Event::Internal(InternalEvent::Breakpoint(Box::new( + move |_| { + eprintln!("[BlockTrace] ({}, {}) -> block", func_idx, evt_idx); + Ok(()) + }, + )))) + } + Event::Wasm(Operator::Loop { .. }) => { + let func_idx = self.func_idx; + let evt_idx = self.evt_idx; + sink.push(op); + sink.push(Event::Internal(InternalEvent::Breakpoint(Box::new( + move |_| { + eprintln!("[BlockTrace] ({}, {}) -> loop", func_idx, evt_idx); + Ok(()) + }, + )))) + } + Event::Wasm(Operator::If { .. }) => { + let func_idx = self.func_idx; + let evt_idx = self.evt_idx; + sink.push(op); + sink.push(Event::Internal(InternalEvent::Breakpoint(Box::new( + move |_| { + eprintln!("[BlockTrace] ({}, {}) -> if", func_idx, evt_idx); + Ok(()) + }, + )))) + } + Event::Wasm(Operator::Else { .. }) => { + let func_idx = self.func_idx; + let evt_idx = self.evt_idx; + sink.push(op); + sink.push(Event::Internal(InternalEvent::Breakpoint(Box::new( + move |_| { + eprintln!("[BlockTrace] ({}, {}) -> else", func_idx, evt_idx); + Ok(()) + }, + )))) + } + _ => { + sink.push(op); + } + } + self.evt_idx += 1; + Ok(()) + } +} diff --git a/lib/middleware-common/src/lib.rs b/lib/middleware-common/src/lib.rs index c7900c83a73..ca0523f95e2 100644 --- a/lib/middleware-common/src/lib.rs +++ b/lib/middleware-common/src/lib.rs @@ -10,5 +10,6 @@ #![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")] #![doc(html_logo_url = "https://avatars3.githubusercontent.com/u/44205449?s=200&v=4")] +pub mod block_trace; pub mod call_trace; pub mod metering; From b0b0983eb8e27a1fae1e46764e3e97b283787ded Mon Sep 17 00:00:00 2001 From: losfair Date: Sun, 13 Oct 2019 20:51:39 +0800 Subject: [PATCH 039/342] Allow accessing execution state in middleware breakpoint handlers. --- lib/runtime-core/src/codegen.rs | 3 ++- lib/runtime-core/src/fault.rs | 36 ++++++++++++++++++++++----------- lib/runtime-core/src/state.rs | 13 +++++++++--- 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index e69b9637c6b..46534fac107 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -3,6 +3,7 @@ use crate::{ backend::{Backend, CacheGen, Compiler, CompilerConfig, Features, Token}, cache::{Artifact, Error as CacheError}, error::{CompileError, CompileResult}, + fault::FaultInfo, module::{ModuleInfo, ModuleInner}, structures::Map, types::{FuncIndex, FuncSig, SigIndex}, @@ -49,7 +50,7 @@ impl fmt::Debug for InternalEvent { } pub struct BreakpointInfo<'a> { - pub fault: Option<&'a dyn Any>, + pub fault: Option<&'a FaultInfo>, } pub trait ModuleCodeGenerator, RM: RunnableModule, E: Debug> { diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index 51d00d52e25..ae0bf65c98c 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -20,7 +20,7 @@ pub mod raw { use crate::codegen::{BreakpointInfo, BreakpointMap}; use crate::state::x64::{build_instance_image, read_stack, X64Register, GPR, XMM}; -use crate::state::CodeVersion; +use crate::state::{CodeVersion, ExecutionStateImage}; use crate::vm; use libc::{mmap, mprotect, siginfo_t, MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE}; use nix::sys::signal::{ @@ -344,17 +344,9 @@ extern "C" fn signal_trap_handler( } let ctx: &mut vm::Ctx = &mut **CURRENT_CTX.with(|x| x.get()); - let rsp = fault.known_registers[X64Register::GPR(GPR::RSP).to_index().0].unwrap(); - - let es_image = CURRENT_CODE_VERSIONS.with(|versions| { - let versions = versions.borrow(); - read_stack( - || versions.iter(), - rsp as usize as *const u64, - fault.known_registers, - Some(fault.ip.get() as u64), - ) - }); + let es_image = fault + .read_stack(None) + .expect("fault.read_stack() failed. Broken invariants?"); if is_suspend_signal { let image = build_instance_image(ctx, es_image); @@ -431,6 +423,26 @@ pub struct FaultInfo { pub known_registers: [Option; 24], } +impl FaultInfo { + pub unsafe fn read_stack(&self, max_depth: Option) -> Option { + let rsp = match self.known_registers[X64Register::GPR(GPR::RSP).to_index().0] { + Some(x) => x, + None => return None, + }; + + Some(CURRENT_CODE_VERSIONS.with(|versions| { + let versions = versions.borrow(); + read_stack( + || versions.iter(), + rsp as usize as *const u64, + self.known_registers, + Some(self.ip.get() as u64), + max_depth, + ) + })) + } +} + #[cfg(all(target_os = "linux", target_arch = "aarch64"))] pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> FaultInfo { #[allow(dead_code)] diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index e31e55bb476..4a1bf5d0ad4 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -875,12 +875,19 @@ pub mod x64 { mut stack: *const u64, initially_known_registers: [Option; 24], mut initial_address: Option, + max_depth: Option, ) -> ExecutionStateImage { let mut known_registers: [Option; 24] = initially_known_registers; let mut results: Vec = vec![]; let mut was_baseline = true; - for _ in 0.. { + for depth in 0.. { + if let Some(max_depth) = max_depth { + if depth >= max_depth { + return ExecutionStateImage { frames: results }; + } + } + let ret_addr = initial_address.take().unwrap_or_else(|| { let x = *stack; stack = stack.offset(1); @@ -891,7 +898,7 @@ pub mod x64 { let mut is_baseline: Option = None; for version in versions() { - println!("Lookup IP: {:x}", ret_addr); + //println!("Lookup IP: {:x}", ret_addr); match version .msm .lookup_call_ip(ret_addr as usize, version.base) @@ -1079,7 +1086,7 @@ pub mod x64 { stack: wasm_stack, locals: wasm_locals, }; - println!("WFS = {:?}", wfs); + //println!("WFS = {:?}", wfs); results.push(wfs); } From ba7e2b70edb24441e4e91a46235e75ecc3521ef7 Mon Sep 17 00:00:00 2001 From: losfair Date: Sun, 13 Oct 2019 20:51:48 +0800 Subject: [PATCH 040/342] Add block-trace flag to CLI. --- src/bin/wasmer.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index e54fddd93ce..4cd4cd58e4f 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -179,6 +179,10 @@ struct Run { #[structopt(long = "call-trace")] call_trace: bool, + // Enable the BlockTrace middleware. + #[structopt(long = "block-trace")] + block_trace: 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 /// help commands and error messages of the running wasm program @@ -834,6 +838,10 @@ fn get_compiler_by_backend(backend: Backend, opts: &Run) -> Option Date: Mon, 14 Oct 2019 20:23:10 +0800 Subject: [PATCH 041/342] Emit state information for internal breakpoints. --- lib/singlepass-backend/src/codegen_x64.rs | 31 ++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 08320d1494a..0fe81aa7bc1 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -18,7 +18,8 @@ use std::{ }; use wasmer_runtime_core::{ backend::{ - sys::Memory, Backend, CacheGen, CompilerConfig, MemoryBoundCheckMode, RunnableModule, Token, + get_inline_breakpoint_size, sys::Memory, Architecture, Backend, CacheGen, CompilerConfig, + MemoryBoundCheckMode, RunnableModule, Token, }, cache::{Artifact, Error as CacheError}, codegen::*, @@ -40,6 +41,11 @@ use wasmer_runtime_core::{ }; use wasmparser::{Operator, Type as WpType, TypeOrFuncType as WpTypeOrFuncType}; +#[cfg(target_arch = "aarch64")] +static ARCH: Architecture = Architecture::Aarch64; +#[cfg(target_arch = "x86_64")] +static ARCH: Architecture = Architecture::X64; + #[cfg(target_arch = "x86_64")] lazy_static! { /// Performs a System V call to `target` with [stack_top..stack_base] as the argument list, from right to left. @@ -687,6 +693,28 @@ impl X64FunctionCode { .insert(m.state.wasm_inst_offset, SuspendOffset::Trappable(offset)); } + fn mark_inline_breakpoint( + a: &mut Assembler, + m: &Machine, + fsm: &mut FunctionStateMap, + control_stack: &mut [ControlFrame], + ) { + let state_diff_id = Self::get_state_diff(m, fsm, control_stack); + let offset = a.get_offset().0; + fsm.trappable_offsets.insert( + offset, + OffsetInfo { + end_offset: offset + + get_inline_breakpoint_size(ARCH, Backend::Singlepass) + .expect("cannot get inline breakpoint size"), + activate_offset: offset, + diff_id: state_diff_id, + }, + ); + fsm.wasm_offset_to_target_offset + .insert(m.state.wasm_inst_offset, SuspendOffset::Trappable(offset)); + } + /// Moves `loc` to a valid location for `div`/`idiv`. fn emit_relaxed_xdiv( a: &mut Assembler, @@ -1909,6 +1937,7 @@ impl FunctionCodeGenerator for X64FunctionCode { .as_mut() .unwrap() .insert(a.get_offset(), callback); + Self::mark_trappable(a, &self.machine, &mut self.fsm, &mut self.control_stack); a.emit_inline_breakpoint(InlineBreakpointType::Middleware); } InternalEvent::FunctionBegin(_) | InternalEvent::FunctionEnd => {} From 2e532fa66da1c15bf66bdf9972a019b3fed1335f Mon Sep 17 00:00:00 2001 From: losfair Date: Mon, 14 Oct 2019 20:23:27 +0800 Subject: [PATCH 042/342] Preserve fault.ip when calling middleware. --- lib/runtime-core/src/fault.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index ae0bf65c98c..b2b7a415dd4 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -272,8 +272,6 @@ extern "C" fn signal_trap_handler( v.backend, std::slice::from_raw_parts(ip as *const u8, magic_size), ) { - fault.ip.set(ip + magic_size); - match ib.ty { InlineBreakpointType::Trace => {} InlineBreakpointType::Middleware => { @@ -292,6 +290,8 @@ extern "C" fn signal_trap_handler( } _ => println!("Unknown breakpoint type: {:?}", ib.ty), } + + fault.ip.set(ip + magic_size); return true; } break; From e5f7dc82746fd600c8f2bcb912aa72ddf5b18816 Mon Sep 17 00:00:00 2001 From: losfair Date: Mon, 14 Oct 2019 20:23:43 +0800 Subject: [PATCH 043/342] Print the last frame in block trace output. --- lib/middleware-common/src/block_trace.rs | 72 ++++++++++++++++++++---- 1 file changed, 60 insertions(+), 12 deletions(-) diff --git a/lib/middleware-common/src/block_trace.rs b/lib/middleware-common/src/block_trace.rs index cb4ae3f21ca..f104ab086b4 100644 --- a/lib/middleware-common/src/block_trace.rs +++ b/lib/middleware-common/src/block_trace.rs @@ -34,8 +34,16 @@ impl FunctionMiddleware for BlockTrace { let evt_idx = self.evt_idx; sink.push(op); sink.push(Event::Internal(InternalEvent::Breakpoint(Box::new( - move |_| { - eprintln!("[BlockTrace] ({}, {}) -> enter_func", func_idx, evt_idx); + move |info| { + eprintln!( + "[BlockTrace] ({}, {}) -> enter_func % {:?}", + func_idx, + evt_idx, + info.fault + .and_then(|x| unsafe { x.read_stack(Some(1)) }) + .unwrap() + .frames[0] + ); Ok(()) }, )))) @@ -45,8 +53,16 @@ impl FunctionMiddleware for BlockTrace { let evt_idx = self.evt_idx; sink.push(op); sink.push(Event::Internal(InternalEvent::Breakpoint(Box::new( - move |_| { - eprintln!("[BlockTrace] ({}, {}) -> leave_call", func_idx, evt_idx); + move |info| { + eprintln!( + "[BlockTrace] ({}, {}) -> leave_call % {:?}", + func_idx, + evt_idx, + info.fault + .and_then(|x| unsafe { x.read_stack(Some(1)) }) + .unwrap() + .frames[0] + ); Ok(()) }, )))) @@ -56,8 +72,16 @@ impl FunctionMiddleware for BlockTrace { let evt_idx = self.evt_idx; sink.push(op); sink.push(Event::Internal(InternalEvent::Breakpoint(Box::new( - move |_| { - eprintln!("[BlockTrace] ({}, {}) -> block", func_idx, evt_idx); + move |info| { + eprintln!( + "[BlockTrace] ({}, {}) -> block % {:?}", + func_idx, + evt_idx, + info.fault + .and_then(|x| unsafe { x.read_stack(Some(1)) }) + .unwrap() + .frames[0] + ); Ok(()) }, )))) @@ -67,8 +91,16 @@ impl FunctionMiddleware for BlockTrace { let evt_idx = self.evt_idx; sink.push(op); sink.push(Event::Internal(InternalEvent::Breakpoint(Box::new( - move |_| { - eprintln!("[BlockTrace] ({}, {}) -> loop", func_idx, evt_idx); + move |info| { + eprintln!( + "[BlockTrace] ({}, {}) -> loop % {:?}", + func_idx, + evt_idx, + info.fault + .and_then(|x| unsafe { x.read_stack(Some(1)) }) + .unwrap() + .frames[0] + ); Ok(()) }, )))) @@ -78,8 +110,16 @@ impl FunctionMiddleware for BlockTrace { let evt_idx = self.evt_idx; sink.push(op); sink.push(Event::Internal(InternalEvent::Breakpoint(Box::new( - move |_| { - eprintln!("[BlockTrace] ({}, {}) -> if", func_idx, evt_idx); + move |info| { + eprintln!( + "[BlockTrace] ({}, {}) -> if % {:?}", + func_idx, + evt_idx, + info.fault + .and_then(|x| unsafe { x.read_stack(Some(1)) }) + .unwrap() + .frames[0] + ); Ok(()) }, )))) @@ -89,8 +129,16 @@ impl FunctionMiddleware for BlockTrace { let evt_idx = self.evt_idx; sink.push(op); sink.push(Event::Internal(InternalEvent::Breakpoint(Box::new( - move |_| { - eprintln!("[BlockTrace] ({}, {}) -> else", func_idx, evt_idx); + move |info| { + eprintln!( + "[BlockTrace] ({}, {}) -> else % {:?}", + func_idx, + evt_idx, + info.fault + .and_then(|x| unsafe { x.read_stack(Some(1)) }) + .unwrap() + .frames[0] + ); Ok(()) }, )))) From ee88c459e589db661aeee8418392866f598b0c2a Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 15 Oct 2019 21:55:04 +0800 Subject: [PATCH 044/342] Allow arbitrary size of `disp`. --- .../src/translator_aarch64.rs | 188 +++++++++--------- 1 file changed, 94 insertions(+), 94 deletions(-) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 55649db4993..0c373a9e583 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -224,9 +224,9 @@ macro_rules! binop_gpr_mem { match ($sz, $src, $dst) { (Size::S32, Location::GPR(src), Location::Memory(base, disp)) => { if disp >= 0 { - dynasm!($assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!($assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!($assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!($assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, { assert!(imm < 32); if disp >= 0 { - dynasm!($assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!($assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, { assert!(imm < 32); if disp >= 0 { - dynasm!($assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!($assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after; data: ; .dword x as i32; after: ; ldr w_tmp1, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after; data: ; .qword x as i64; after: ; ldr x_tmp1, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after; data: ; .dword x as i32; after: ; ldr w_tmp1, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after; data: ; .dword x as i32; after: ; ldr w_tmp1, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, dynasm!(self ; br X(map_gpr(x).x())), Location::Memory(base, disp) => { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after @@ -811,9 +811,9 @@ impl Emitter for Assembler { } (Size::S64, Location::Imm32(left), Location::Memory(base, disp)) => { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after @@ -835,9 +835,9 @@ impl Emitter for Assembler { ), (Size::S32, Location::GPR(left), Location::Memory(base, disp)) => { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, { if disp >= 0 { - dynasm!(assembler ; add x_tmp3, X(map_gpr(base).x()), disp as u32); + dynasm!(assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, Date: Tue, 15 Oct 2019 22:00:33 +0800 Subject: [PATCH 045/342] Fix disp < 0 case. --- .../src/translator_aarch64.rs | 94 +++++++++---------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 0c373a9e583..d2ae87a8b14 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -226,7 +226,7 @@ macro_rules! binop_gpr_mem { if disp >= 0 { dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after; data: ; .dword x as i32; after: ; ldr w_tmp1, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after; data: ; .qword x as i64; after: ; ldr x_tmp1, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after; data: ; .dword x as i32; after: ; ldr w_tmp1, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after; data: ; .dword x as i32; after: ; ldr w_tmp1, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after @@ -813,7 +813,7 @@ impl Emitter for Assembler { if disp >= 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after @@ -837,7 +837,7 @@ impl Emitter for Assembler { if disp >= 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, = 0 { dynasm!(assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, Date: Tue, 15 Oct 2019 22:12:08 +0800 Subject: [PATCH 046/342] Skip inline non-instruction data. --- .../src/translator_aarch64.rs | 188 +++++++++--------- 1 file changed, 94 insertions(+), 94 deletions(-) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index d2ae87a8b14..cdc86dcf3fc 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -224,9 +224,9 @@ macro_rules! binop_gpr_mem { match ($sz, $src, $dst) { (Size::S32, Location::GPR(src), Location::Memory(base, disp)) => { if disp >= 0 { - dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { assert!(imm < 32); if disp >= 0 { - dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { assert!(imm < 32); if disp >= 0 { - dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!($assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, after; data: ; .dword x as i32; after: ; ldr w_tmp1, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, after; data: ; .qword x as i64; after: ; ldr x_tmp1, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, after; data: ; .dword x as i32; after: ; ldr w_tmp1, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, after; data: ; .dword x as i32; after: ; ldr w_tmp1, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, dynasm!(self ; br X(map_gpr(x).x())), Location::Memory(base, disp) => { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, after @@ -811,9 +811,9 @@ impl Emitter for Assembler { } (Size::S64, Location::Imm32(left), Location::Memory(base, disp)) => { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, after @@ -835,9 +835,9 @@ impl Emitter for Assembler { ), (Size::S32, Location::GPR(left), Location::Memory(base, disp)) => { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(assembler ; disp: ; .dword disp as i32 ; ldr w_tmp3, after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, Date: Thu, 17 Oct 2019 23:00:32 +0800 Subject: [PATCH 047/342] Increment aarch64 virtual stack size to 1MB. --- 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 0fe81aa7bc1..20c9a0c2155 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -189,7 +189,7 @@ lazy_static! { ; br x30 // LR ; v_65536: - ; .qword 65536 + ; .qword 1048576 ); let buf = assembler.finalize().unwrap(); let ret = unsafe { ::std::mem::transmute(buf.ptr(offset)) }; From 00242cdd7f9548bef2ed7d84efa950e3ae2e9a2f Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 17 Oct 2019 23:00:50 +0800 Subject: [PATCH 048/342] Fix LEA simulation on aarch64. --- lib/singlepass-backend/src/translator_aarch64.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index cdc86dcf3fc..83352284cc8 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -566,16 +566,16 @@ impl Emitter for Assembler { match (sz, src, dst) { (Size::S32, Location::Memory(src, disp), Location::GPR(dst)) => { if disp >= 0 { - dynasm!(self ; add W(map_gpr(dst).x()), W(map_gpr(src).x()), disp as u32); + dynasm!(self ; b >after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { if disp >= 0 { - dynasm!(self ; add X(map_gpr(dst).x()), X(map_gpr(src).x()), disp as u32); + dynasm!(self ; b >after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, unreachable!(), From 4df797363933f77f2a30e3ddadc7bbddfafca379 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 17 Oct 2019 23:34:24 +0800 Subject: [PATCH 049/342] Add mov variants. --- lib/singlepass-backend/src/translator_aarch64.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 83352284cc8..6415c5e7373 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -484,6 +484,9 @@ impl Emitter for Assembler { } dynasm!(self ; b >after; data: ; .dword x as i32; after: ; ldr w_tmp1, { + dynasm!(self ; b >after; data: ; .dword x as u8 as i32; after: ; ldr W(map_gpr(dst).x()), { if disp >= 0 { dynasm!(self ; b >after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after; data: ; .dword x as i32; after: ; ldr w_tmp1, { + dynasm!(self ; b >after; data: ; .dword x as u16 as i32; after: ; ldr W(map_gpr(dst).x()), { dynasm!(self ; fmov S(map_xmm(dst).v()), S(map_xmm(src).v())); } From 3f35a74b84acaf3cf9d999aff646754a31d2c761 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 17 Oct 2019 23:40:44 +0800 Subject: [PATCH 050/342] Two more mov variants. --- lib/singlepass-backend/src/translator_aarch64.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 6415c5e7373..32fb15c0b7c 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -487,6 +487,9 @@ impl Emitter for Assembler { (Size::S8, Location::Imm32(x), Location::GPR(dst)) => { dynasm!(self ; b >after; data: ; .dword x as u8 as i32; after: ; ldr W(map_gpr(dst).x()), { + dynasm!(self ; b >after; data: ; .dword x as u8 as i32; after: ; ldr W(map_gpr(dst).x()), { if disp >= 0 { dynasm!(self ; b >after ; disp: ; .dword disp ; after: ; ldr w_tmp3, { dynasm!(self ; b >after; data: ; .dword x as u16 as i32; after: ; ldr W(map_gpr(dst).x()), { + dynasm!(self ; b >after; data: ; .dword x as u16 as i32; after: ; ldr W(map_gpr(dst).x()), { dynasm!(self ; fmov S(map_xmm(dst).v()), S(map_xmm(src).v())); } From a0572966182eb193ac66d8ab485256ab4674cc3a Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 17 Oct 2019 23:45:58 +0800 Subject: [PATCH 051/342] (S32, Imm64, GPR) --- lib/singlepass-backend/src/translator_aarch64.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 32fb15c0b7c..002aff2dda0 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -427,6 +427,9 @@ impl Emitter for Assembler { (Size::S32, Location::Imm32(x), Location::GPR(dst)) => { dynasm!(self ; b >after; data: ; .dword x as i32; after: ; ldr W(map_gpr(dst).x()), { + dynasm!(self ; b >after; data: ; .dword x as i32; after: ; ldr W(map_gpr(dst).x()), { dynasm!(self ; mov X(map_gpr(dst).x()), X(map_gpr(src).x())); } From cd0b49e661dd7c9a1f249708f5acf99db0fa7071 Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 18 Oct 2019 00:18:15 +0800 Subject: [PATCH 052/342] popcnt for aarch64. --- .../src/translator_aarch64.rs | 80 ++++++++++++++++++- 1 file changed, 76 insertions(+), 4 deletions(-) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 002aff2dda0..34b4353ed58 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -109,6 +109,10 @@ pub fn get_aarch64_assembler() -> Assembler { ; .alias w_tmp2, w26 ; .alias x_tmp3, x25 ; .alias w_tmp3, w25 + ; .alias d_tmp1, d28 + ; .alias d_tmp2, d27 + ; .alias v_tmp1, v28 + ; .alias v_tmp2, v27 ); a } @@ -1102,10 +1106,78 @@ impl Emitter for Assembler { emit_clz_variant(self, sz, &src, &dst, true); } fn emit_popcnt(&mut self, sz: Size, src: Location, dst: Location) { - dynasm!( - self - ; .dword 0 ; .dword 90 // TODO: Implement - ); + match sz { + Size::S32 => { + match src { + Location::GPR(src) => dynasm!( + self + ; mov w_tmp1, W(map_gpr(src).x()) + ), + Location::Memory(base, disp) => { + if disp >= 0 { + dynasm!(self ; b >after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, unreachable!(), + } + match dst { + Location::GPR(dst) => { + dynasm!( + self + ; mov v_tmp1.S[0], w_tmp1 + ; cnt v_tmp1.B16, v_tmp1.B16 + ; mov W(map_gpr(dst).x()), v_tmp1.S[0] + ; add W(map_gpr(dst).x()), W(map_gpr(dst).x()), W(map_gpr(dst).x()), lsr 16 + ; and W(map_gpr(dst).x()), W(map_gpr(dst).x()), 31 + ); + } + _ => unreachable!(), + } + } + Size::S64 => { + match src { + Location::GPR(src) => dynasm!( + self + ; mov x_tmp1, X(map_gpr(src).x()) + ), + Location::Memory(base, disp) => { + if disp >= 0 { + dynasm!(self ; b >after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, unreachable!(), + } + match dst { + Location::GPR(dst) => { + dynasm!( + self + ; mov v_tmp1.D[0], x_tmp1 + ; cnt v_tmp1.B16, v_tmp1.B16 + ; mov x_tmp1, v_tmp1.D[0] + ; mov X(map_gpr(dst).x()), x_tmp1 + ; add X(map_gpr(dst).x()), X(map_gpr(dst).x()), x_tmp1, lsr 16 + ; add X(map_gpr(dst).x()), X(map_gpr(dst).x()), x_tmp1, lsr 32 + ; add X(map_gpr(dst).x()), X(map_gpr(dst).x()), x_tmp1, lsr 48 + ; and X(map_gpr(dst).x()), X(map_gpr(dst).x()), 63 + ); + } + _ => unreachable!(), + } + } + _ => unreachable!(), + } } fn emit_movzx(&mut self, sz_src: Size, src: Location, _sz_dst: Size, dst: Location) { match (sz_src, src, dst) { From 8d95e637f2b19235fa40255516b9f049da0fcb63 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Fri, 1 Nov 2019 17:38:43 -0700 Subject: [PATCH 053/342] Add probable fix of memory leak in trampoline code --- lib/runtime-c-api/src/trampoline.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime-c-api/src/trampoline.rs b/lib/runtime-c-api/src/trampoline.rs index 923622aa509..ed7b8971bf0 100644 --- a/lib/runtime-c-api/src/trampoline.rs +++ b/lib/runtime-c-api/src/trampoline.rs @@ -61,7 +61,7 @@ pub unsafe extern "C" fn wasmer_trampoline_buffer_builder_build( #[allow(clippy::cast_ptr_alignment)] pub unsafe extern "C" fn wasmer_trampoline_buffer_destroy(buffer: *mut wasmer_trampoline_buffer_t) { if !buffer.is_null() { - Box::from_raw(buffer); + Box::from_raw(buffer as *mut TrampolineBuffer); } } From ef5faccb76178a7efb1eb8c79783c98426e2a59d Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 4 Nov 2019 13:45:19 -0800 Subject: [PATCH 054/342] Update __wasi_rights_t and __wasi_signal_t with published changes --- lib/wasi/src/syscalls/types.rs | 56 ++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/lib/wasi/src/syscalls/types.rs b/lib/wasi/src/syscalls/types.rs index d0082ef69fb..060f3cd435c 100644 --- a/lib/wasi/src/syscalls/types.rs +++ b/lib/wasi/src/syscalls/types.rs @@ -457,8 +457,8 @@ pub const __WASI_RIGHT_FD_FILESTAT_GET: u64 = 1 << 21; pub const __WASI_RIGHT_FD_FILESTAT_SET_SIZE: u64 = 1 << 22; pub const __WASI_RIGHT_FD_FILESTAT_SET_TIMES: u64 = 1 << 23; pub const __WASI_RIGHT_PATH_SYMLINK: u64 = 1 << 24; -pub const __WASI_RIGHT_PATH_UNLINK_FILE: u64 = 1 << 25; -pub const __WASI_RIGHT_PATH_REMOVE_DIRECTORY: u64 = 1 << 26; +pub const __WASI_RIGHT_PATH_REMOVE_DIRECTORY: u64 = 1 << 25; +pub const __WASI_RIGHT_PATH_UNLINK_FILE: u64 = 1 << 26; pub const __WASI_RIGHT_POLL_FD_READWRITE: u64 = 1 << 27; pub const __WASI_RIGHT_SOCK_SHUTDOWN: u64 = 1 << 28; @@ -522,32 +522,36 @@ pub const __WASI_SHUT_WR: u8 = 1 << 1; pub type __wasi_siflags_t = u16; pub type __wasi_signal_t = u8; -pub const __WASI_SIGABRT: u8 = 0; -pub const __WASI_SIGALRM: u8 = 1; -pub const __WASI_SIGBUS: u8 = 2; -pub const __WASI_SIGCHLD: u8 = 3; -pub const __WASI_SIGCONT: u8 = 4; -pub const __WASI_SIGFPE: u8 = 5; -pub const __WASI_SIGHUP: u8 = 6; -pub const __WASI_SIGILL: u8 = 7; -pub const __WASI_SIGINT: u8 = 8; +pub const __WASI_SIGHUP: u8 = 1; +pub const __WASI_SIGINT: u8 = 2; +pub const __WASI_SIGQUIT: u8 = 3; +pub const __WASI_SIGILL: u8 = 4; +pub const __WASI_SIGTRAP: u8 = 5; +pub const __WASI_SIGABRT: u8 = 6; +pub const __WASI_SIGBUS: u8 = 7; +pub const __WASI_SIGFPE: u8 = 8; pub const __WASI_SIGKILL: u8 = 9; -pub const __WASI_SIGPIPE: u8 = 10; -pub const __WASI_SIGQUIT: u8 = 11; -pub const __WASI_SIGSEGV: u8 = 12; -pub const __WASI_SIGSTOP: u8 = 13; -pub const __WASI_SIGSYS: u8 = 14; +pub const __WASI_SIGUSR1: u8 = 10; +pub const __WASI_SIGSEGV: u8 = 11; +pub const __WASI_SIGUSR2: u8 = 12; +pub const __WASI_SIGPIPE: u8 = 13; +pub const __WASI_SIGALRM: u8 = 14; pub const __WASI_SIGTERM: u8 = 15; -pub const __WASI_SIGTRAP: u8 = 16; -pub const __WASI_SIGTSTP: u8 = 17; -pub const __WASI_SIGTTIN: u8 = 18; -pub const __WASI_SIGTTOU: u8 = 19; -pub const __WASI_SIGURG: u8 = 20; -pub const __WASI_SIGUSR1: u8 = 21; -pub const __WASI_SIGUSR2: u8 = 22; -pub const __WASI_SIGVTALRM: u8 = 23; -pub const __WASI_SIGXCPU: u8 = 24; -pub const __WASI_SIGXFSZ: u8 = 25; +pub const __WASI_SIGCHLD: u8 = 16; +pub const __WASI_SIGCONT: u8 = 17; +pub const __WASI_SIGSTOP: u8 = 18; +pub const __WASI_SIGTSTP: u8 = 19; +pub const __WASI_SIGTTIN: u8 = 20; +pub const __WASI_SIGTTOU: u8 = 21; +pub const __WASI_SIGURG: u8 = 22; +pub const __WASI_SIGXCPU: u8 = 23; +pub const __WASI_SIGXFSZ: u8 = 24; +pub const __WASI_SIGVTALRM: u8 = 25; +pub const __WASI_SIGPROF: u8 = 26; +pub const __WASI_SIGWINCH: u8 = 27; +pub const __WASI_SIGPOLL: u8 = 28; +pub const __WASI_SIGPWR: u8 = 29; +pub const __WASI_SIGSYS: u8 = 30; pub type __wasi_subclockflags_t = u16; pub const __WASI_SUBSCRIPTION_CLOCK_ABSTIME: u16 = 1 << 0; From 015491ea77665bdeee7566f8ab2364f1dab51ded Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 6 Nov 2019 01:43:41 +0800 Subject: [PATCH 055/342] Add floating point instructions. --- .../src/translator_aarch64.rs | 171 ++++++++---------- 1 file changed, 76 insertions(+), 95 deletions(-) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 34b4353ed58..d72d389ca0b 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -117,6 +117,12 @@ pub fn get_aarch64_assembler() -> Assembler { a } +const X_TMP1: u32 = 27; +const X_TMP2: u32 = 26; +const X_TMP3: u32 = 25; +const V_TMP1: u32 = 28; +const V_TMP2: u32 = 27; + macro_rules! binop_imm32_gpr { ($ins:ident, $assembler:tt, $sz:expr, $src:expr, $dst:expr, $otherwise:block) => { match ($sz, $src, $dst) { @@ -371,6 +377,45 @@ macro_rules! binop_shift { } } +macro_rules! avx_fn { + ($ins:ident, $width:ident, $width_int:ident, $name:ident) => { + fn $name(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + match src2 { + XMMOrMemory::XMM(src2) => dynasm!(self ; $ins $width(map_xmm(dst).v()), $width(map_xmm(src1).v()), $width(map_xmm(src2).v())), + XMMOrMemory::Memory(base, disp) => { + if disp >= 0 { + dynasm!(self ; b >after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { + fn $name(&mut self, src1: XMM, _src2: XMMOrMemory, dst: XMM) { + dynasm!(self ; $ins $width(map_xmm(dst).v()), $width(map_xmm(src1).v())); + } + } +} + +macro_rules! avx_fn_cvt { + ($ins:ident, $width_src:ident, $width_dst:ident, $name:ident) => { + fn $name(&mut self, src1: XMM, _src2: XMMOrMemory, dst: XMM) { + dynasm!(self ; $ins $width_dst(map_xmm(dst).v()), $width_src(map_xmm(src1).v())); + } + } +} + impl Emitter for Assembler { type Label = DynamicLabel; type Offset = AssemblyOffset; @@ -1281,49 +1326,37 @@ impl Emitter for Assembler { dynasm!(self ; .dword 0 ; .dword 29) } - fn emit_vaddss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vaddsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vsubss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vsubsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vmulss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vmulsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vdivss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vdivsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vmaxss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vmaxsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vminss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vminsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - - fn emit_vcmpeqss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vcmpeqsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } + avx_fn!(fadd, S, W, emit_vaddss); + avx_fn!(fsub, S, W, emit_vsubss); + avx_fn!(fmul, S, W, emit_vmulss); + avx_fn!(fdiv, S, W, emit_vdivss); + avx_fn!(fmax, S, W, emit_vmaxss); + avx_fn!(fmin, S, W, emit_vminss); + avx_fn!(fcmgt, S, W, emit_vcmpgtss); + avx_fn!(fcmge, S, W, emit_vcmpgess); + avx_fn!(fcmeq, S, W, emit_vcmpeqss); + avx_fn_unop!(fsqrt, S, emit_vsqrtss); + avx_fn_unop!(frintn, S, emit_vroundss_nearest); // to nearest with ties to even + avx_fn_unop!(frintm, S, emit_vroundss_floor); // toward minus infinity + avx_fn_unop!(frintp, S, emit_vroundss_ceil); // toward positive infinity + avx_fn_unop!(frintz, S, emit_vroundss_trunc); // toward zero + avx_fn_cvt!(fcvt, S, D, emit_vcvtss2sd); + + avx_fn!(fadd, D, X, emit_vaddsd); + avx_fn!(fsub, D, X, emit_vsubsd); + avx_fn!(fmul, D, X, emit_vmulsd); + avx_fn!(fdiv, D, X, emit_vdivsd); + avx_fn!(fmax, D, X, emit_vmaxsd); + avx_fn!(fmin, D, X, emit_vminsd); + avx_fn!(fcmgt, D, X, emit_vcmpgtsd); + avx_fn!(fcmge, D, X, emit_vcmpgesd); + avx_fn!(fcmeq, D, X, emit_vcmpeqsd); + avx_fn_unop!(fsqrt, D, emit_vsqrtsd); + avx_fn_unop!(frintn, D, emit_vroundsd_nearest); // to nearest with ties to even + avx_fn_unop!(frintm, D, emit_vroundsd_floor); // toward minus infinity + avx_fn_unop!(frintp, D, emit_vroundsd_ceil); // toward positive infinity + avx_fn_unop!(frintz, D, emit_vroundsd_trunc); // toward zero + avx_fn_cvt!(fcvt, D, S, emit_vcvtsd2ss); fn emit_vcmpneqss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { dynasm!(self ; .dword 0 ; .dword 29) @@ -1346,58 +1379,6 @@ impl Emitter for Assembler { dynasm!(self ; .dword 0 ; .dword 29) } - fn emit_vcmpgtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vcmpgtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - - fn emit_vcmpgess(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vcmpgesd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - - fn emit_vsqrtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vsqrtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - - fn emit_vroundss_nearest(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vroundss_floor(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vroundss_ceil(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vroundss_trunc(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vroundsd_nearest(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vroundsd_floor(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vroundsd_ceil(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vroundsd_trunc(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - - fn emit_vcvtss2sd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_vcvtsd2ss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) - } fn emit_ucomiss(&mut self, src: XMMOrMemory, dst: XMM) { dynasm!(self ; .dword 0 ; .dword 29) From dc437bb4e7e891add122838bf0909a3e9a371c12 Mon Sep 17 00:00:00 2001 From: nlewycky Date: Tue, 5 Nov 2019 11:31:14 -0800 Subject: [PATCH 056/342] Fix typo in comment. --- lib/runtime-core/src/fault.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index bc21052fae0..5aaf81af94a 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -290,7 +290,7 @@ extern "C" fn signal_trap_handler( ); es_image.print_backtrace_if_needed(); } - // Just let the error propagate otherrwise + // Just let the error propagate otherwise } true From 177c507a4eb08c28a2af864be19bb1e5f45bab78 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 31 Oct 2019 22:04:00 +0100 Subject: [PATCH 057/342] feat(runtime-core) Introduce `vm::FuncCtx`. `vm::FuncCtx` replaces `vm::Ctx` as first argument passed to host functions (aka imported functions). --- lib/runtime-core/src/backing.rs | 29 +++++++++++++++++++++++------ lib/runtime-core/src/instance.rs | 8 ++++---- lib/runtime-core/src/typed_func.rs | 6 ++++-- lib/runtime-core/src/vm.rs | 21 ++++++++++++++++----- 4 files changed, 47 insertions(+), 17 deletions(-) diff --git a/lib/runtime-core/src/backing.rs b/lib/runtime-core/src/backing.rs index ff21e9195f1..d413ef00e2a 100644 --- a/lib/runtime-core/src/backing.rs +++ b/lib/runtime-core/src/backing.rs @@ -15,7 +15,7 @@ use crate::{ }, vm, }; -use std::{fmt::Debug, slice}; +use std::{fmt::Debug, ptr, slice}; pub const INTERNALS_SIZE: usize = 256; @@ -384,7 +384,7 @@ impl LocalBacking { LocalOrImport::Import(imported_func_index) => { let vm::ImportedFunc { func, vmctx } = imports.vm_functions[imported_func_index]; - (func, vmctx) + (func, vmctx as _) } }; @@ -417,7 +417,7 @@ impl LocalBacking { LocalOrImport::Import(imported_func_index) => { let vm::ImportedFunc { func, vmctx } = imports.vm_functions[imported_func_index]; - (func, vmctx) + (func, vmctx as _) } }; @@ -541,6 +541,15 @@ impl ImportBacking { } } +impl Drop for ImportBacking { + fn drop(&mut self) { + for (_imported_func_index, imported_func) in (*self.vm_functions).iter_mut() { + let _: Box = unsafe { Box::from_raw(imported_func.vmctx) }; + imported_func.vmctx = ptr::null_mut(); + } + } +} + fn import_functions( module: &ModuleInner, imports: &ImportObject, @@ -564,6 +573,7 @@ fn import_functions( let import = imports.maybe_with_namespace(namespace, |namespace| namespace.get_export(name)); + dbg!(vmctx); match import { Some(Export::Function { func, @@ -573,9 +583,16 @@ fn import_functions( if *expected_sig == *signature { functions.push(vm::ImportedFunc { func: func.inner(), - vmctx: match ctx { - Context::External(ctx) => ctx, - Context::Internal => vmctx, + vmctx: { + let _ = match ctx { + Context::External(ctx) => ctx, + Context::Internal => vmctx, + }; + + Box::into_raw(Box::new(vm::FuncCtx { + vmctx, + func_env: ptr::null_mut(), + })) }, }); } else { diff --git a/lib/runtime-core/src/instance.rs b/lib/runtime-core/src/instance.rs index 85e9f8f768b..2716e272ad6 100644 --- a/lib/runtime-core/src/instance.rs +++ b/lib/runtime-core/src/instance.rs @@ -111,7 +111,7 @@ impl Instance { let ctx_ptr = match start_index.local_or_import(&instance.module.info) { LocalOrImport::Local(_) => instance.inner.vmctx, LocalOrImport::Import(imported_func_index) => { - instance.inner.import_backing.vm_functions[imported_func_index].vmctx + instance.inner.import_backing.vm_functions[imported_func_index].vmctx as _ } }; @@ -196,7 +196,7 @@ impl Instance { let ctx = match func_index.local_or_import(&self.module.info) { LocalOrImport::Local(_) => self.inner.vmctx, LocalOrImport::Import(imported_func_index) => { - self.inner.import_backing.vm_functions[imported_func_index].vmctx + self.inner.import_backing.vm_functions[imported_func_index].vmctx as _ } }; @@ -449,7 +449,7 @@ impl InstanceInner { let imported_func = &self.import_backing.vm_functions[imported_func_index]; ( imported_func.func as *const _, - Context::External(imported_func.vmctx), + Context::External(imported_func.vmctx as _), ) } }; @@ -575,7 +575,7 @@ fn call_func_with_index( let ctx_ptr = match func_index.local_or_import(info) { LocalOrImport::Local(_) => local_ctx, LocalOrImport::Import(imported_func_index) => { - import_backing.vm_functions[imported_func_index].vmctx + import_backing.vm_functions[imported_func_index].vmctx as _ } }; diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 2a38beb1e97..8e0819985bd 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -490,7 +490,7 @@ 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>( - vmctx: &mut vm::Ctx $( , $x: <$x as WasmExternType>::Native )* + func_ctx: &mut vm::FuncCtx $( , $x: <$x as WasmExternType>::Native )* ) -> Rets::CStruct where $( $x: WasmExternType, )* @@ -498,6 +498,7 @@ macro_rules! impl_traits { Trap: TrapEarly, FN: Fn(&mut vm::Ctx, $( $x, )*) -> Trap, { + let vmctx = unsafe { &mut *func_ctx.vmctx }; let f: FN = unsafe { mem::transmute_copy(&()) }; let err = match panic::catch_unwind( @@ -548,7 +549,7 @@ 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>( - vmctx: &mut vm::Ctx $( , $x: <$x as WasmExternType>::Native )* + func_ctx: &mut vm::FuncCtx $( , $x: <$x as WasmExternType>::Native )* ) -> Rets::CStruct where $( $x: WasmExternType, )* @@ -556,6 +557,7 @@ macro_rules! impl_traits { Trap: TrapEarly, FN: Fn($( $x, )*) -> Trap, { + let vmctx = unsafe { &mut *func_ctx.vmctx }; let f: FN = unsafe { mem::transmute_copy(&()) }; let err = match panic::catch_unwind( diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index 2bb734a04d8..adc33f2c5e2 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -498,19 +498,30 @@ impl Ctx { } } -enum InnerFunc {} /// Used to provide type safety (ish) for passing around function pointers. -/// The typesystem ensures this cannot be dereferenced since an -/// empty enum cannot actually exist. #[repr(C)] -pub struct Func(InnerFunc); +pub struct Func { + _private: [u8; 0], +} + +#[repr(C)] +pub struct FuncEnv { + _private: [u8; 0], +} + +#[derive(Debug)] +#[repr(C)] +pub struct FuncCtx { + pub vmctx: *mut Ctx, + pub func_env: *mut FuncEnv, +} /// An imported function, which contains the vmctx that owns this function. #[derive(Debug, Clone)] #[repr(C)] pub struct ImportedFunc { pub func: *const Func, - pub vmctx: *mut Ctx, + pub vmctx: *mut FuncCtx, } // manually implemented because ImportedFunc contains raw pointers directly; `Func` is marked Send (But `Ctx` actually isn't! (TODO: review this, shouldn't `Ctx` be Send?)) From e002c377efcf104c49297efbd0e217b6385045e8 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 4 Nov 2019 11:45:09 +0100 Subject: [PATCH 058/342] feat(runtime-core) `vm::ImportedFunc` and `vm::FuncCtx` have `NonNull` pointers. --- lib/runtime-core/src/backing.rs | 30 +++++++++++++++++------------- lib/runtime-core/src/instance.rs | 26 +++++++++++++++++++------- lib/runtime-core/src/typed_func.rs | 4 ++-- lib/runtime-core/src/vm.rs | 4 ++-- 4 files changed, 40 insertions(+), 24 deletions(-) diff --git a/lib/runtime-core/src/backing.rs b/lib/runtime-core/src/backing.rs index d413ef00e2a..f9b320b45ea 100644 --- a/lib/runtime-core/src/backing.rs +++ b/lib/runtime-core/src/backing.rs @@ -15,7 +15,11 @@ use crate::{ }, vm, }; -use std::{fmt::Debug, ptr, slice}; +use std::{ + fmt::Debug, + ptr::{self, NonNull}, + slice, +}; pub const INTERNALS_SIZE: usize = 256; @@ -382,9 +386,9 @@ impl LocalBacking { vmctx, ), LocalOrImport::Import(imported_func_index) => { - let vm::ImportedFunc { func, vmctx } = + let vm::ImportedFunc { func, func_ctx } = imports.vm_functions[imported_func_index]; - (func, vmctx as _) + (func, unsafe { func_ctx.as_ref() }.vmctx.as_ptr()) } }; @@ -415,9 +419,9 @@ impl LocalBacking { vmctx, ), LocalOrImport::Import(imported_func_index) => { - let vm::ImportedFunc { func, vmctx } = + let vm::ImportedFunc { func, func_ctx } = imports.vm_functions[imported_func_index]; - (func, vmctx as _) + (func, unsafe { func_ctx.as_ref() }.vmctx.as_ptr()) } }; @@ -544,8 +548,7 @@ impl ImportBacking { impl Drop for ImportBacking { fn drop(&mut self) { for (_imported_func_index, imported_func) in (*self.vm_functions).iter_mut() { - let _: Box = unsafe { Box::from_raw(imported_func.vmctx) }; - imported_func.vmctx = ptr::null_mut(); + let _: Box = unsafe { Box::from_raw(imported_func.func_ctx.as_ptr()) }; } } } @@ -583,16 +586,17 @@ fn import_functions( if *expected_sig == *signature { functions.push(vm::ImportedFunc { func: func.inner(), - vmctx: { + func_ctx: { let _ = match ctx { Context::External(ctx) => ctx, Context::Internal => vmctx, }; - Box::into_raw(Box::new(vm::FuncCtx { - vmctx, + NonNull::new(Box::into_raw(Box::new(vm::FuncCtx { + vmctx: NonNull::new(vmctx).expect("`vmctx` must not be null."), func_env: ptr::null_mut(), - })) + }))) + .unwrap() }, }); } else { @@ -622,8 +626,8 @@ fn import_functions( None => { if imports.allow_missing_functions { functions.push(vm::ImportedFunc { - func: ::std::ptr::null(), - vmctx: ::std::ptr::null_mut(), + func: ptr::null(), + func_ctx: unsafe { NonNull::new_unchecked(ptr::null_mut()) }, // TODO: Non-sense… }); } else { link_errors.push(LinkError::ImportNotFound { diff --git a/lib/runtime-core/src/instance.rs b/lib/runtime-core/src/instance.rs index 2716e272ad6..5cf92a312f9 100644 --- a/lib/runtime-core/src/instance.rs +++ b/lib/runtime-core/src/instance.rs @@ -110,9 +110,13 @@ impl Instance { let ctx_ptr = match start_index.local_or_import(&instance.module.info) { LocalOrImport::Local(_) => instance.inner.vmctx, - LocalOrImport::Import(imported_func_index) => { - instance.inner.import_backing.vm_functions[imported_func_index].vmctx as _ + LocalOrImport::Import(imported_func_index) => unsafe { + instance.inner.import_backing.vm_functions[imported_func_index] + .func_ctx + .as_ref() } + .vmctx + .as_ptr(), }; let sig_index = *instance @@ -195,9 +199,13 @@ impl Instance { let ctx = match func_index.local_or_import(&self.module.info) { LocalOrImport::Local(_) => self.inner.vmctx, - LocalOrImport::Import(imported_func_index) => { - self.inner.import_backing.vm_functions[imported_func_index].vmctx as _ + LocalOrImport::Import(imported_func_index) => unsafe { + self.inner.import_backing.vm_functions[imported_func_index] + .func_ctx + .as_ref() } + .vmctx + .as_ptr(), }; let func_wasm_inner = self @@ -449,7 +457,7 @@ impl InstanceInner { let imported_func = &self.import_backing.vm_functions[imported_func_index]; ( imported_func.func as *const _, - Context::External(imported_func.vmctx as _), + Context::External(unsafe { imported_func.func_ctx.as_ref() }.vmctx.as_ptr()), ) } }; @@ -574,9 +582,13 @@ fn call_func_with_index( let ctx_ptr = match func_index.local_or_import(info) { LocalOrImport::Local(_) => local_ctx, - LocalOrImport::Import(imported_func_index) => { - import_backing.vm_functions[imported_func_index].vmctx as _ + LocalOrImport::Import(imported_func_index) => unsafe { + import_backing.vm_functions[imported_func_index] + .func_ctx + .as_ref() } + .vmctx + .as_ptr(), }; let wasm = runnable diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 8e0819985bd..049dfc16130 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -498,7 +498,7 @@ macro_rules! impl_traits { Trap: TrapEarly, FN: Fn(&mut vm::Ctx, $( $x, )*) -> Trap, { - let vmctx = unsafe { &mut *func_ctx.vmctx }; + let vmctx = unsafe { func_ctx.vmctx.as_mut() }; let f: FN = unsafe { mem::transmute_copy(&()) }; let err = match panic::catch_unwind( @@ -557,7 +557,7 @@ macro_rules! impl_traits { Trap: TrapEarly, FN: Fn($( $x, )*) -> Trap, { - let vmctx = unsafe { &mut *func_ctx.vmctx }; + let vmctx = unsafe { func_ctx.vmctx.as_mut() }; let f: FN = unsafe { mem::transmute_copy(&()) }; let err = match panic::catch_unwind( diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index adc33f2c5e2..fa4d3020bf6 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -512,7 +512,7 @@ pub struct FuncEnv { #[derive(Debug)] #[repr(C)] pub struct FuncCtx { - pub vmctx: *mut Ctx, + pub vmctx: NonNull, pub func_env: *mut FuncEnv, } @@ -521,7 +521,7 @@ pub struct FuncCtx { #[repr(C)] pub struct ImportedFunc { pub func: *const Func, - pub vmctx: *mut FuncCtx, + pub func_ctx: NonNull, } // manually implemented because ImportedFunc contains raw pointers directly; `Func` is marked Send (But `Ctx` actually isn't! (TODO: review this, shouldn't `Ctx` be Send?)) From 6035bd2d9be80c51b169954af206bb3ab4d5887f Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 4 Nov 2019 12:24:30 +0100 Subject: [PATCH 059/342] feat(runtime-core,clif-backend,llvm-backend) Rename an `ImportFunc` offset. `ImportedFunc::offset_vmctx` becomes `ImportedFunc::offset_func_ctx`. --- lib/clif-backend/src/code.rs | 18 ++++++++++-------- lib/llvm-backend/src/stackmap.rs | 2 +- lib/runtime-core/src/vm.rs | 10 ++++++---- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index f1d8489da13..d07b5ce6dda 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -763,20 +763,22 @@ impl FuncEnvironment for FunctionEnvironment { readonly: true, }); - let imported_vmctx_addr = pos.func.create_global_value(ir::GlobalValueData::Load { - base: imported_func_struct_addr, - offset: (vm::ImportedFunc::offset_vmctx() as i32).into(), - global_type: ptr_type, - readonly: true, - }); + let imported_func_ctx_addr = + pos.func.create_global_value(ir::GlobalValueData::Load { + base: imported_func_struct_addr, + offset: (vm::ImportedFunc::offset_func_ctx() as i32).into(), + global_type: ptr_type, + readonly: true, + }); let imported_func_addr = pos.ins().global_value(ptr_type, imported_func_addr); - let imported_vmctx_addr = pos.ins().global_value(ptr_type, imported_vmctx_addr); + let imported_func_ctx_addr = + pos.ins().global_value(ptr_type, imported_func_ctx_addr); let sig_ref = pos.func.dfg.ext_funcs[callee].signature; let mut args = Vec::with_capacity(call_args.len() + 1); - args.push(imported_vmctx_addr); + args.push(imported_func_ctx_addr); args.extend(call_args.iter().cloned()); Ok(pos diff --git a/lib/llvm-backend/src/stackmap.rs b/lib/llvm-backend/src/stackmap.rs index a56c3c6a38d..4a9dbf81633 100644 --- a/lib/llvm-backend/src/stackmap.rs +++ b/lib/llvm-backend/src/stackmap.rs @@ -161,7 +161,7 @@ impl StackmapEntry { ValueSemantic::ImportedFuncCtx(idx) => MachineValue::VmctxDeref(vec![ Ctx::offset_imported_funcs() as usize, vm::ImportedFunc::size() as usize * idx - + vm::ImportedFunc::offset_vmctx() as usize, + + vm::ImportedFunc::offset_func_ctx() as usize, 0, ]), ValueSemantic::DynamicSigindice(idx) => { diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index fa4d3020bf6..1cc228c6548 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -524,7 +524,9 @@ pub struct ImportedFunc { pub func_ctx: NonNull, } -// manually implemented because ImportedFunc contains raw pointers directly; `Func` is marked Send (But `Ctx` actually isn't! (TODO: review this, shouldn't `Ctx` be Send?)) +// manually implemented because ImportedFunc contains raw pointers +// directly; `Func` is marked Send (But `Ctx` actually isn't! (TODO: +// review this, shouldn't `Ctx` be Send?)) unsafe impl Send for ImportedFunc {} impl ImportedFunc { @@ -533,7 +535,7 @@ impl ImportedFunc { 0 * (mem::size_of::() as u8) } - pub fn offset_vmctx() -> u8 { + pub fn offset_func_ctx() -> u8 { 1 * (mem::size_of::() as u8) } @@ -756,8 +758,8 @@ mod vm_offset_tests { ); assert_eq!( - ImportedFunc::offset_vmctx() as usize, - offset_of!(ImportedFunc => vmctx).get_byte_offset(), + ImportedFunc::offset_func_ctx() as usize, + offset_of!(ImportedFunc => func_ctx).get_byte_offset(), ); } From 0e27f2fa72361d6fc90d94240af8c5671db5f571 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 4 Nov 2019 13:02:29 +0100 Subject: [PATCH 060/342] test(runtime-core) Test more host functions as closures. --- lib/runtime-core-tests/tests/imports.rs | 54 +++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/lib/runtime-core-tests/tests/imports.rs b/lib/runtime-core-tests/tests/imports.rs index 69b9040cdc6..61702e5ac36 100644 --- a/lib/runtime-core-tests/tests/imports.rs +++ b/lib/runtime-core-tests/tests/imports.rs @@ -11,21 +11,37 @@ fn imported_functions_forms() { (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_closure" (func $callback_closure (type $type))) (import "env" "callback_fn_with_vmctx" (func $callback_fn_with_vmctx (type $type))) + (import "env" "callback_closure_with_vmctx" (func $callback_closure_with_vmctx (type $type))) (import "env" "callback_fn_trap" (func $callback_fn_trap (type $type))) + (import "env" "callback_closure_trap" (func $callback_closure_trap (type $type))) (import "env" "callback_fn_trap_with_vmctx" (func $callback_fn_trap_with_vmctx (type $type))) + (import "env" "callback_closure_trap_with_vmctx" (func $callback_closure_trap_with_vmctx (type $type))) (func (export "function_fn") (type $type) get_local 0 call $callback_fn) + (func (export "function_closure") (type $type) + get_local 0 + call $callback_closure) (func (export "function_fn_with_vmctx") (type $type) get_local 0 call $callback_fn_with_vmctx) + (func (export "function_closure_with_vmctx") (type $type) + get_local 0 + call $callback_closure_with_vmctx) (func (export "function_fn_trap") (type $type) get_local 0 call $callback_fn_trap) + (func (export "function_closure_trap") (type $type) + get_local 0 + call $callback_closure_trap) (func (export "function_fn_trap_with_vmctx") (type $type) get_local 0 - call $callback_fn_trap_with_vmctx)) + call $callback_fn_trap_with_vmctx) + (func (export "function_closure_trap_with_vmctx") (type $type) + get_local 0 + call $callback_closure_trap_with_vmctx)) "#; let wasm_binary = wat2wasm(MODULE.as_bytes()).expect("WAST not valid or malformed"); @@ -40,9 +56,27 @@ fn imported_functions_forms() { "env" => { "memory" => memory.clone(), "callback_fn" => Func::new(callback_fn), + "callback_closure" => Func::new(|n: i32| -> Result { + Ok(n + 1) + }), "callback_fn_with_vmctx" => Func::new(callback_fn_with_vmctx), + "callback_closure_with_vmctx" => Func::new(|vmctx: &mut vm::Ctx, n: i32| -> Result { + let memory = vmctx.memory(0); + let shift: i32 = memory.view()[0].get(); + + Ok(shift + n + 1) + }), "callback_fn_trap" => Func::new(callback_fn_trap), + "callback_closure_trap" => Func::new(|n: i32| -> Result { + Err(format!("bar {}", n + 1)) + }), "callback_fn_trap_with_vmctx" => Func::new(callback_fn_trap_with_vmctx), + "callback_closure_trap_with_vmctx" => Func::new(|vmctx: &mut vm::Ctx, n: i32| -> Result { + let memory = vmctx.memory(0); + let shift: i32 = memory.view()[0].get(); + + Err(format!("qux {}", shift + n + 1)) + }), }, }; let instance = module.instantiate(&import_object).unwrap(); @@ -99,11 +133,19 @@ fn imported_functions_forms() { } call_and_assert!(function_fn, Ok(2)); + call_and_assert!(function_closure, Ok(2)); call_and_assert!(function_fn_with_vmctx, Ok(2 + SHIFT)); + call_and_assert!(function_closure_with_vmctx, Ok(2 + SHIFT)); call_and_assert!( function_fn_trap, Err(RuntimeError::Error { - data: Box::new(format!("foo {}", 1)) + data: Box::new(format!("foo {}", 2)) + }) + ); + call_and_assert!( + function_closure_trap, + Err(RuntimeError::Error { + data: Box::new(format!("bar {}", 2)) }) ); call_and_assert!( @@ -112,6 +154,12 @@ fn imported_functions_forms() { data: Box::new(format!("baz {}", 2 + SHIFT)) }) ); + call_and_assert!( + function_closure_trap_with_vmctx, + Err(RuntimeError::Error { + data: Box::new(format!("qux {}", 2 + SHIFT)) + }) + ); } fn callback_fn(n: i32) -> Result { @@ -126,7 +174,7 @@ fn callback_fn_with_vmctx(vmctx: &mut vm::Ctx, n: i32) -> Result { } fn callback_fn_trap(n: i32) -> Result { - Err(format!("foo {}", n)) + Err(format!("foo {}", n + 1)) } fn callback_fn_trap_with_vmctx(vmctx: &mut vm::Ctx, n: i32) -> Result { From 2a041f898eb9cc8a70a4dd11c328df18e90c50c8 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 4 Nov 2019 14:14:12 +0100 Subject: [PATCH 061/342] !temp --- lib/runtime-core-tests/tests/imports.rs | 18 ++ lib/runtime-core/src/backing.rs | 24 +-- lib/runtime-core/src/typed_func.rs | 265 ++++++++++++++---------- lib/runtime-core/src/vm.rs | 8 +- 4 files changed, 189 insertions(+), 126 deletions(-) diff --git a/lib/runtime-core-tests/tests/imports.rs b/lib/runtime-core-tests/tests/imports.rs index 61702e5ac36..24fc4ad5f11 100644 --- a/lib/runtime-core-tests/tests/imports.rs +++ b/lib/runtime-core-tests/tests/imports.rs @@ -12,33 +12,46 @@ fn imported_functions_forms() { (import "env" "memory" (memory 1 1)) (import "env" "callback_fn" (func $callback_fn (type $type))) (import "env" "callback_closure" (func $callback_closure (type $type))) + (import "env" "callback_closure_with_env" (func $callback_closure_with_env (type $type))) (import "env" "callback_fn_with_vmctx" (func $callback_fn_with_vmctx (type $type))) (import "env" "callback_closure_with_vmctx" (func $callback_closure_with_vmctx (type $type))) (import "env" "callback_fn_trap" (func $callback_fn_trap (type $type))) (import "env" "callback_closure_trap" (func $callback_closure_trap (type $type))) (import "env" "callback_fn_trap_with_vmctx" (func $callback_fn_trap_with_vmctx (type $type))) (import "env" "callback_closure_trap_with_vmctx" (func $callback_closure_trap_with_vmctx (type $type))) + (func (export "function_fn") (type $type) get_local 0 call $callback_fn) + (func (export "function_closure") (type $type) get_local 0 call $callback_closure) + + (func (export "function_closure_with_env") (type $type) + get_local 0 + call $callback_closure_with_env) + (func (export "function_fn_with_vmctx") (type $type) get_local 0 call $callback_fn_with_vmctx) + (func (export "function_closure_with_vmctx") (type $type) get_local 0 call $callback_closure_with_vmctx) + (func (export "function_fn_trap") (type $type) get_local 0 call $callback_fn_trap) + (func (export "function_closure_trap") (type $type) get_local 0 call $callback_closure_trap) + (func (export "function_fn_trap_with_vmctx") (type $type) get_local 0 call $callback_fn_trap_with_vmctx) + (func (export "function_closure_trap_with_vmctx") (type $type) get_local 0 call $callback_closure_trap_with_vmctx)) @@ -51,6 +64,7 @@ fn imported_functions_forms() { const SHIFT: i32 = 10; memory.view()[0].set(SHIFT); + let shift = 100; let import_object = imports! { "env" => { @@ -59,6 +73,9 @@ fn imported_functions_forms() { "callback_closure" => Func::new(|n: i32| -> Result { Ok(n + 1) }), + "callback_closure_with_env" => Func::new(move |n: i32| -> Result { + Ok(shift + n + 1) + }), "callback_fn_with_vmctx" => Func::new(callback_fn_with_vmctx), "callback_closure_with_vmctx" => Func::new(|vmctx: &mut vm::Ctx, n: i32| -> Result { let memory = vmctx.memory(0); @@ -134,6 +151,7 @@ fn imported_functions_forms() { call_and_assert!(function_fn, Ok(2)); call_and_assert!(function_closure, Ok(2)); + call_and_assert!(function_closure_with_env, Ok(2 + shift)); call_and_assert!(function_fn_with_vmctx, Ok(2 + SHIFT)); call_and_assert!(function_closure_with_vmctx, Ok(2 + SHIFT)); call_and_assert!( diff --git a/lib/runtime-core/src/backing.rs b/lib/runtime-core/src/backing.rs index f9b320b45ea..0f57b2bbf99 100644 --- a/lib/runtime-core/src/backing.rs +++ b/lib/runtime-core/src/backing.rs @@ -586,18 +586,18 @@ fn import_functions( if *expected_sig == *signature { functions.push(vm::ImportedFunc { func: func.inner(), - func_ctx: { - let _ = match ctx { - Context::External(ctx) => ctx, - Context::Internal => vmctx, - }; - - NonNull::new(Box::into_raw(Box::new(vm::FuncCtx { - vmctx: NonNull::new(vmctx).expect("`vmctx` must not be null."), - func_env: ptr::null_mut(), - }))) - .unwrap() - }, + func_ctx: NonNull::new(Box::into_raw(Box::new(vm::FuncCtx { + vmctx: NonNull::new(vmctx).expect("`vmctx` must not be null."), + func_env: match ctx { + Context::External(ctx) => { + NonNull::new(ctx).map(|pointer| { + pointer.cast() // `*mut vm::FuncEnv` was casted to `*mut vm::Ctx` to fit in `Context::External`. Cast it back. + }) + } + Context::Internal => None, + }, + }))) + .unwrap(), }); } else { link_errors.push(LinkError::IncorrectImportSignature { diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 049dfc16130..584749ecf0d 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -175,7 +175,7 @@ where Args: WasmTypeList, Rets: WasmTypeList, { - fn to_raw(&self) -> NonNull; + fn to_raw(self) -> (NonNull, Option>); } pub trait TrapEarly @@ -208,10 +208,12 @@ where } /// Represents a function that can be used by WebAssembly. +#[allow(dead_code)] pub struct Func<'a, Args = (), Rets = (), Inner: Kind = Wasm> { inner: Inner, - f: NonNull, - ctx: *mut vm::Ctx, + func: NonNull, + func_env: Option>, + vmctx: *mut vm::Ctx, _phantom: PhantomData<(&'a (), Args, Rets)>, } @@ -225,19 +227,20 @@ where { pub(crate) unsafe fn from_raw_parts( inner: Wasm, - f: NonNull, - ctx: *mut vm::Ctx, + func: NonNull, + vmctx: *mut vm::Ctx, ) -> Func<'a, Args, Rets, Wasm> { Func { inner, - f, - ctx, + func, + func_env: None, + vmctx, _phantom: PhantomData, } } pub fn get_vm_func(&self) -> NonNull { - self.f + self.func } } @@ -246,15 +249,18 @@ where Args: WasmTypeList, Rets: WasmTypeList, { - pub fn new(f: F) -> Func<'a, Args, Rets, Host> + pub fn new(func: F) -> Func<'a, Args, Rets, Host> where Kind: ExternalFunctionKind, F: ExternalFunction, { + let (func, func_env) = func.to_raw(); + Func { inner: Host(()), - f: f.to_raw(), - ctx: ptr::null_mut(), + func, + func_env, + vmctx: ptr::null_mut(), _phantom: PhantomData, } } @@ -391,7 +397,7 @@ where Rets: WasmTypeList, { pub fn call(&self, a: A) -> Result { - unsafe { ::call(a, self.f, self.inner, self.ctx) } + unsafe { ::call(a, self.func, self.inner, self.vmctx) } } } @@ -482,57 +488,75 @@ macro_rules! impl_traits { $( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly, - FN: Fn(&mut vm::Ctx $( , $x )*) -> Trap, + FN: Fn(&mut vm::Ctx $( , $x )*) -> Trap + 'static, { #[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>( - func_ctx: &mut vm::FuncCtx $( , $x: <$x as WasmExternType>::Native )* - ) -> Rets::CStruct - where - $( $x: WasmExternType, )* - Rets: WasmTypeList, - Trap: TrapEarly, - FN: Fn(&mut vm::Ctx, $( $x, )*) -> Trap, - { - let vmctx = unsafe { func_ctx.vmctx.as_mut() }; - let f: FN = unsafe { mem::transmute_copy(&()) }; - - let err = match panic::catch_unwind( - panic::AssertUnwindSafe( - || { - f(vmctx $( , 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) - } + fn to_raw(self) -> (NonNull, Option>) { + /// 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>( + func_ctx: &mut vm::FuncCtx $( , $x: <$x as WasmExternType>::Native )* + ) -> Rets::CStruct + where + $( $x: WasmExternType, )* + Rets: WasmTypeList, + Trap: TrapEarly, + FN: Fn(&mut vm::Ctx, $( $x, )*) -> Trap, + { + dbg!(func_ctx.vmctx.as_ptr()); + + let vmctx = unsafe { func_ctx.vmctx.as_mut() }; + let func_env = func_ctx.func_env; + + dbg!(func_env); + + let func: &FN = match func_env { + Some(func_env) => unsafe { + let func: NonNull = func_env.cast(); + + &*func.as_ptr() + }, + None => unsafe { mem::transmute_copy(&()) } + }; + + let err = match panic::catch_unwind( + panic::AssertUnwindSafe( + || { + func(vmctx $( , 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() } + + let func_env: Option> = + // `FN` is a function pointer, or a closure + // _without_ a captured environment. + if mem::size_of::() == 0 { + None + } + // `FN` is a closure _with_ a captured + // environment. Grab it. + else { + NonNull::new(Box::into_raw(Box::new(self))).map(NonNull::cast) + }; + + dbg!(func_env); + + ( + NonNull::new(wrap::<$( $x, )* Rets, Trap, Self> as *mut vm::Func).unwrap(), + func_env + ) } } @@ -541,57 +565,75 @@ macro_rules! impl_traits { $( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly, - FN: Fn($( $x, )*) -> Trap, + FN: Fn($( $x, )*) -> Trap + 'static, { #[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>( - func_ctx: &mut vm::FuncCtx $( , $x: <$x as WasmExternType>::Native )* - ) -> Rets::CStruct - where - $( $x: WasmExternType, )* - Rets: WasmTypeList, - Trap: TrapEarly, - FN: Fn($( $x, )*) -> Trap, - { - let vmctx = unsafe { func_ctx.vmctx.as_mut() }; - 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) - } + fn to_raw(self) -> (NonNull, Option>) { + /// 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>( + func_ctx: &mut vm::FuncCtx $( , $x: <$x as WasmExternType>::Native )* + ) -> Rets::CStruct + where + $( $x: WasmExternType, )* + Rets: WasmTypeList, + Trap: TrapEarly, + FN: Fn($( $x, )*) -> Trap, + { + dbg!(func_ctx.vmctx.as_ptr()); + + let vmctx = unsafe { func_ctx.vmctx.as_mut() }; + let func_env = func_ctx.func_env; + + dbg!(func_env); + + let func: &FN = match func_env { + Some(func_env) => unsafe { + let func: NonNull = func_env.cast(); + + &*func.as_ptr() + }, + None => unsafe { mem::transmute_copy(&()) } + }; + + let err = match panic::catch_unwind( + panic::AssertUnwindSafe( + || { + func($( 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() } + + let func_env: Option> = + // `FN` is a function pointer, or a closure + // _without_ a captured environment. + if mem::size_of::() == 0 { + None + } + // `FN` is a closure _with_ a captured + // environment. Grab it. + else { + NonNull::new(Box::into_raw(Box::new(self))).map(NonNull::cast) + }; + + dbg!(func_env); + + ( + NonNull::new(wrap::<$( $x, )* Rets, Trap, Self> as *mut vm::Func).unwrap(), + func_env + ) } } @@ -606,9 +648,9 @@ macro_rules! impl_traits { unsafe { <( $( $x ),* ) as WasmTypeList>::call( ( $( $x ),* ), - self.f, + self.func, self.inner, - self.ctx + self.vmctx ) } } @@ -646,8 +688,11 @@ where Inner: Kind, { fn to_export(&self) -> Export { - let func = unsafe { FuncPointer::new(self.f.as_ptr()) }; - let ctx = Context::Internal; + let func = unsafe { FuncPointer::new(self.func.as_ptr()) }; + let ctx = match self.func_env { + Some(func_env) => Context::External(func_env.cast().as_ptr()), + None => Context::Internal, + }; let signature = Arc::new(FuncSig::new(Args::types(), Rets::types())); Export::Function { diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index 1cc228c6548..dc92c788f9f 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -512,16 +512,16 @@ pub struct FuncEnv { #[derive(Debug)] #[repr(C)] pub struct FuncCtx { - pub vmctx: NonNull, - pub func_env: *mut FuncEnv, + pub(crate) vmctx: NonNull, + pub(crate) func_env: Option>, } /// An imported function, which contains the vmctx that owns this function. #[derive(Debug, Clone)] #[repr(C)] pub struct ImportedFunc { - pub func: *const Func, - pub func_ctx: NonNull, + pub(crate) func: *const Func, + pub(crate) func_ctx: NonNull, } // manually implemented because ImportedFunc contains raw pointers From 3b34a9187a3c941b48455b1bb07c9ea65d0bc79b Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 4 Nov 2019 15:13:10 +0100 Subject: [PATCH 062/342] chore(runtime-core) Remove `dbg!`. --- lib/runtime-core/src/backing.rs | 2 +- lib/runtime-core/src/typed_func.rs | 12 ------------ 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/lib/runtime-core/src/backing.rs b/lib/runtime-core/src/backing.rs index 0f57b2bbf99..c6fffb55329 100644 --- a/lib/runtime-core/src/backing.rs +++ b/lib/runtime-core/src/backing.rs @@ -576,7 +576,7 @@ fn import_functions( let import = imports.maybe_with_namespace(namespace, |namespace| namespace.get_export(name)); - dbg!(vmctx); + match import { Some(Export::Function { func, diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 584749ecf0d..28693359ba9 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -503,13 +503,9 @@ macro_rules! impl_traits { Trap: TrapEarly, FN: Fn(&mut vm::Ctx, $( $x, )*) -> Trap, { - dbg!(func_ctx.vmctx.as_ptr()); - let vmctx = unsafe { func_ctx.vmctx.as_mut() }; let func_env = func_ctx.func_env; - dbg!(func_env); - let func: &FN = match func_env { Some(func_env) => unsafe { let func: NonNull = func_env.cast(); @@ -551,8 +547,6 @@ macro_rules! impl_traits { NonNull::new(Box::into_raw(Box::new(self))).map(NonNull::cast) }; - dbg!(func_env); - ( NonNull::new(wrap::<$( $x, )* Rets, Trap, Self> as *mut vm::Func).unwrap(), func_env @@ -580,13 +574,9 @@ macro_rules! impl_traits { Trap: TrapEarly, FN: Fn($( $x, )*) -> Trap, { - dbg!(func_ctx.vmctx.as_ptr()); - let vmctx = unsafe { func_ctx.vmctx.as_mut() }; let func_env = func_ctx.func_env; - dbg!(func_env); - let func: &FN = match func_env { Some(func_env) => unsafe { let func: NonNull = func_env.cast(); @@ -628,8 +618,6 @@ macro_rules! impl_traits { NonNull::new(Box::into_raw(Box::new(self))).map(NonNull::cast) }; - dbg!(func_env); - ( NonNull::new(wrap::<$( $x, )* Rets, Trap, Self> as *mut vm::Func).unwrap(), func_env From a52b4b2280fb74109c1be8e29e9f8a539288d5d2 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 4 Nov 2019 15:21:09 +0100 Subject: [PATCH 063/342] test(runtime-core) Test closures with a captured environment. --- lib/runtime-core-tests/tests/imports.rs | 57 ++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/lib/runtime-core-tests/tests/imports.rs b/lib/runtime-core-tests/tests/imports.rs index 24fc4ad5f11..128a552c53c 100644 --- a/lib/runtime-core-tests/tests/imports.rs +++ b/lib/runtime-core-tests/tests/imports.rs @@ -15,10 +15,12 @@ fn imported_functions_forms() { (import "env" "callback_closure_with_env" (func $callback_closure_with_env (type $type))) (import "env" "callback_fn_with_vmctx" (func $callback_fn_with_vmctx (type $type))) (import "env" "callback_closure_with_vmctx" (func $callback_closure_with_vmctx (type $type))) + (import "env" "callback_closure_with_vmctx_and_env" (func $callback_closure_with_vmctx_and_env (type $type))) (import "env" "callback_fn_trap" (func $callback_fn_trap (type $type))) (import "env" "callback_closure_trap" (func $callback_closure_trap (type $type))) (import "env" "callback_fn_trap_with_vmctx" (func $callback_fn_trap_with_vmctx (type $type))) (import "env" "callback_closure_trap_with_vmctx" (func $callback_closure_trap_with_vmctx (type $type))) + (import "env" "callback_closure_trap_with_vmctx_and_env" (func $callback_closure_trap_with_vmctx_and_env (type $type))) (func (export "function_fn") (type $type) get_local 0 @@ -40,6 +42,10 @@ fn imported_functions_forms() { get_local 0 call $callback_closure_with_vmctx) + (func (export "function_closure_with_vmctx_and_env") (type $type) + get_local 0 + call $callback_closure_with_vmctx_and_env) + (func (export "function_fn_trap") (type $type) get_local 0 call $callback_fn_trap) @@ -54,7 +60,11 @@ fn imported_functions_forms() { (func (export "function_closure_trap_with_vmctx") (type $type) get_local 0 - call $callback_closure_trap_with_vmctx)) + call $callback_closure_trap_with_vmctx) + + (func (export "function_closure_trap_with_vmctx_and_env") (type $type) + get_local 0 + call $callback_closure_trap_with_vmctx_and_env)) "#; let wasm_binary = wat2wasm(MODULE.as_bytes()).expect("WAST not valid or malformed"); @@ -69,31 +79,67 @@ fn imported_functions_forms() { let import_object = imports! { "env" => { "memory" => memory.clone(), + + // Regular function. "callback_fn" => Func::new(callback_fn), + + // Closure without a captured environment. "callback_closure" => Func::new(|n: i32| -> Result { Ok(n + 1) }), + + // Closure with a captured environment (a single variable + an instance of `Memory`). "callback_closure_with_env" => Func::new(move |n: i32| -> Result { + let shift = shift + memory.view::()[0].get(); + Ok(shift + n + 1) }), + + // Regular function with an explicit `vmctx`. "callback_fn_with_vmctx" => Func::new(callback_fn_with_vmctx), + + // Closure without a captured environment but with an explicit `vmctx`. "callback_closure_with_vmctx" => Func::new(|vmctx: &mut vm::Ctx, n: i32| -> Result { let memory = vmctx.memory(0); let shift: i32 = memory.view()[0].get(); Ok(shift + n + 1) }), + + // Closure with a captured environment (a single variable) and with an explicit `vmctx`. + "callback_closure_with_vmctx_and_env" => Func::new(move |vmctx: &mut vm::Ctx, n: i32| -> Result { + let memory = vmctx.memory(0); + let shift = shift + memory.view::()[0].get(); + + Ok(shift + n + 1) + }), + + // Trap a regular function. "callback_fn_trap" => Func::new(callback_fn_trap), + + // Trap a closure without a captured environment. "callback_closure_trap" => Func::new(|n: i32| -> Result { Err(format!("bar {}", n + 1)) }), + + // Trap a regular function with an explicit `vmctx`. "callback_fn_trap_with_vmctx" => Func::new(callback_fn_trap_with_vmctx), + + // Trap a closure without a captured environment but with an explicit `vmctx`. "callback_closure_trap_with_vmctx" => Func::new(|vmctx: &mut vm::Ctx, n: i32| -> Result { let memory = vmctx.memory(0); let shift: i32 = memory.view()[0].get(); Err(format!("qux {}", shift + n + 1)) }), + + // Trap a closure with a captured environment (a single variable) and with an explicit `vmctx`. + "callback_closure_trap_with_vmctx_and_env" => Func::new(move |vmctx: &mut vm::Ctx, n: i32| -> Result { + let memory = vmctx.memory(0); + let shift = shift + memory.view::()[0].get(); + + Err(format!("! {}", shift + n + 1)) + }), }, }; let instance = module.instantiate(&import_object).unwrap(); @@ -151,9 +197,10 @@ fn imported_functions_forms() { call_and_assert!(function_fn, Ok(2)); call_and_assert!(function_closure, Ok(2)); - call_and_assert!(function_closure_with_env, Ok(2 + shift)); + call_and_assert!(function_closure_with_env, Ok(2 + shift + SHIFT)); call_and_assert!(function_fn_with_vmctx, Ok(2 + SHIFT)); call_and_assert!(function_closure_with_vmctx, Ok(2 + SHIFT)); + call_and_assert!(function_closure_with_vmctx_and_env, Ok(2 + shift + SHIFT)); call_and_assert!( function_fn_trap, Err(RuntimeError::Error { @@ -178,6 +225,12 @@ fn imported_functions_forms() { data: Box::new(format!("qux {}", 2 + SHIFT)) }) ); + call_and_assert!( + function_closure_trap_with_vmctx_and_env, + Err(RuntimeError::Error { + data: Box::new(format!("! {}", 2 + shift + SHIFT)) + }) + ); } fn callback_fn(n: i32) -> Result { From 3435ce436bc0feb3c867c24b7a7a71b1cc1e3dd1 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 4 Nov 2019 15:40:20 +0100 Subject: [PATCH 064/342] test(runtime-core) Extract `assert` as tests. --- lib/runtime-core-tests/tests/imports.rs | 242 +++++++++++++----------- 1 file changed, 136 insertions(+), 106 deletions(-) diff --git a/lib/runtime-core-tests/tests/imports.rs b/lib/runtime-core-tests/tests/imports.rs index 128a552c53c..bba5050f1ae 100644 --- a/lib/runtime-core-tests/tests/imports.rs +++ b/lib/runtime-core-tests/tests/imports.rs @@ -1,11 +1,64 @@ use wasmer_runtime_core::{ compile_with, error::RuntimeError, imports, memory::Memory, typed_func::Func, - types::MemoryDescriptor, units::Pages, vm, + types::MemoryDescriptor, units::Pages, vm, Instance, }; use wasmer_runtime_core_tests::{get_compiler, wat2wasm}; -#[test] -fn imported_functions_forms() { +macro_rules! call_and_assert { + ($instance:ident, $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 + ) + ), + } + }; +} + +const SHIFT: i32 = 10; +const shift: i32 = 100; + +fn imported_functions_forms(test: &dyn Fn(&Instance)) { const MODULE: &str = r#" (module (type $type (func (param i32) (result i32))) @@ -72,9 +125,7 @@ fn imported_functions_forms() { 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 shift = 100; let import_object = imports! { "env" => { @@ -90,9 +141,9 @@ fn imported_functions_forms() { // Closure with a captured environment (a single variable + an instance of `Memory`). "callback_closure_with_env" => Func::new(move |n: i32| -> Result { - let shift = shift + memory.view::()[0].get(); + let shift_ = shift + memory.view::()[0].get(); - Ok(shift + n + 1) + Ok(shift_ + n + 1) }), // Regular function with an explicit `vmctx`. @@ -101,17 +152,17 @@ fn imported_functions_forms() { // Closure without a captured environment but with an explicit `vmctx`. "callback_closure_with_vmctx" => Func::new(|vmctx: &mut vm::Ctx, n: i32| -> Result { let memory = vmctx.memory(0); - let shift: i32 = memory.view()[0].get(); + let shift_: i32 = memory.view()[0].get(); - Ok(shift + n + 1) + Ok(shift_ + n + 1) }), // Closure with a captured environment (a single variable) and with an explicit `vmctx`. "callback_closure_with_vmctx_and_env" => Func::new(move |vmctx: &mut vm::Ctx, n: i32| -> Result { let memory = vmctx.memory(0); - let shift = shift + memory.view::()[0].get(); + let shift_ = shift + memory.view::()[0].get(); - Ok(shift + n + 1) + Ok(shift_ + n + 1) }), // Trap a regular function. @@ -128,109 +179,23 @@ fn imported_functions_forms() { // Trap a closure without a captured environment but with an explicit `vmctx`. "callback_closure_trap_with_vmctx" => Func::new(|vmctx: &mut vm::Ctx, n: i32| -> Result { let memory = vmctx.memory(0); - let shift: i32 = memory.view()[0].get(); + let shift_: i32 = memory.view()[0].get(); - Err(format!("qux {}", shift + n + 1)) + Err(format!("qux {}", shift_ + n + 1)) }), // Trap a closure with a captured environment (a single variable) and with an explicit `vmctx`. "callback_closure_trap_with_vmctx_and_env" => Func::new(move |vmctx: &mut vm::Ctx, n: i32| -> Result { let memory = vmctx.memory(0); - let shift = shift + memory.view::()[0].get(); + let shift_ = shift + memory.view::()[0].get(); - Err(format!("! {}", shift + n + 1)) + Err(format!("! {}", shift_ + n + 1)) }), }, }; 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, Ok(2)); - call_and_assert!(function_closure, Ok(2)); - call_and_assert!(function_closure_with_env, Ok(2 + shift + SHIFT)); - call_and_assert!(function_fn_with_vmctx, Ok(2 + SHIFT)); - call_and_assert!(function_closure_with_vmctx, Ok(2 + SHIFT)); - call_and_assert!(function_closure_with_vmctx_and_env, Ok(2 + shift + SHIFT)); - call_and_assert!( - function_fn_trap, - Err(RuntimeError::Error { - data: Box::new(format!("foo {}", 2)) - }) - ); - call_and_assert!( - function_closure_trap, - Err(RuntimeError::Error { - data: Box::new(format!("bar {}", 2)) - }) - ); - call_and_assert!( - function_fn_trap_with_vmctx, - Err(RuntimeError::Error { - data: Box::new(format!("baz {}", 2 + SHIFT)) - }) - ); - call_and_assert!( - function_closure_trap_with_vmctx, - Err(RuntimeError::Error { - data: Box::new(format!("qux {}", 2 + SHIFT)) - }) - ); - call_and_assert!( - function_closure_trap_with_vmctx_and_env, - Err(RuntimeError::Error { - data: Box::new(format!("! {}", 2 + shift + SHIFT)) - }) - ); + test(&instance); } fn callback_fn(n: i32) -> Result { @@ -239,9 +204,9 @@ fn callback_fn(n: i32) -> Result { fn callback_fn_with_vmctx(vmctx: &mut vm::Ctx, n: i32) -> Result { let memory = vmctx.memory(0); - let shift: i32 = memory.view()[0].get(); + let shift_: i32 = memory.view()[0].get(); - Ok(shift + n + 1) + Ok(shift_ + n + 1) } fn callback_fn_trap(n: i32) -> Result { @@ -250,7 +215,72 @@ fn callback_fn_trap(n: i32) -> Result { 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(); + let shift_: i32 = memory.view()[0].get(); - Err(format!("baz {}", shift + n + 1)) + Err(format!("baz {}", shift_ + n + 1)) } + +macro_rules! test { + ($test_name:ident, $function:ident, $expected_value:expr) => { + #[test] + fn $test_name() { + imported_functions_forms(&|instance| { + call_and_assert!(instance, $function, $expected_value); + }); + } + }; +} + +test!(test_fn, function_fn, Ok(2)); +test!(test_closure, function_closure, Ok(2)); +test!( + test_closure_with_env, + function_closure_with_env, + Ok(2 + shift + SHIFT) +); +test!(test_fn_with_vmctx, function_fn_with_vmctx, Ok(2 + SHIFT)); +test!( + test_closure_with_vmctx, + function_closure_with_vmctx, + Ok(2 + SHIFT) +); +test!( + test_closure_with_vmctx_and_env, + function_closure_with_vmctx_and_env, + Ok(2 + shift + SHIFT) +); +test!( + test_fn_trap, + function_fn_trap, + Err(RuntimeError::Error { + data: Box::new(format!("foo {}", 2)) + }) +); +test!( + test_closure_trap, + function_closure_trap, + Err(RuntimeError::Error { + data: Box::new(format!("bar {}", 2)) + }) +); +test!( + test_fn_trap_with_vmctx, + function_fn_trap_with_vmctx, + Err(RuntimeError::Error { + data: Box::new(format!("baz {}", 2 + SHIFT)) + }) +); +test!( + test_closure_trap_with_vmctx, + function_closure_trap_with_vmctx, + Err(RuntimeError::Error { + data: Box::new(format!("qux {}", 2 + SHIFT)) + }) +); +test!( + test_closure_trap_with_vmctx_and_env, + function_closure_trap_with_vmctx_and_env, + Err(RuntimeError::Error { + data: Box::new(format!("! {}", 2 + shift + SHIFT)) + }) +); From 81326cee13f09f76bd80250f4703d63e7108b9a9 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 4 Nov 2019 21:45:23 +0100 Subject: [PATCH 065/342] doc(runtime-core) Write more documentation. --- lib/runtime-core/src/typed_func.rs | 52 ++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 28693359ba9..6bc287bae3b 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -208,7 +208,6 @@ where } /// Represents a function that can be used by WebAssembly. -#[allow(dead_code)] pub struct Func<'a, Args = (), Rets = (), Inner: Kind = Wasm> { inner: Inner, func: NonNull, @@ -492,7 +491,14 @@ macro_rules! impl_traits { { #[allow(non_snake_case)] fn to_raw(self) -> (NonNull, Option>) { - /// This is required for the llvm backend to be able to unwind through this function. + // The `wrap` function is a wrapper around the + // imported function. It manages the argument passed + // to the imported function (in this case, the + // `vmctx` along with the regular WebAssembly + // arguments), and it manages the trapping. + // + // It is also 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>( func_ctx: &mut vm::FuncCtx $( , $x: <$x as WasmExternType>::Native )* @@ -503,22 +509,36 @@ macro_rules! impl_traits { Trap: TrapEarly, FN: Fn(&mut vm::Ctx, $( $x, )*) -> Trap, { + // Extract `vm::Ctx` from `vm::FuncCtx`. The + // pointer is always non-null. let vmctx = unsafe { func_ctx.vmctx.as_mut() }; + + // Extract `vm::FuncEnv` from `vm::FuncCtx`. let func_env = func_ctx.func_env; let func: &FN = match func_env { + // The imported function is a closure with a + // captured environment. Some(func_env) => unsafe { let func: NonNull = func_env.cast(); &*func.as_ptr() }, + + // The imported function is a regular function + // or a closure without a captured + // environment. None => unsafe { mem::transmute_copy(&()) } }; + // Catch unwind in case of errors. let err = match panic::catch_unwind( panic::AssertUnwindSafe( || { func(vmctx $( , WasmExternType::from_native($x) )* ).report() + // ^^^^^ The imported function + // expects `vm::Ctx` as first + // argument; provide it. } ) ) { @@ -530,11 +550,15 @@ macro_rules! impl_traits { Err(err) => err, }; + // At this point, there is an error that needs to + // be trapped. unsafe { (&*vmctx.module).runnable_module.do_early_trap(err) } } + // Extract the captured environment of the imported + // function if any. let func_env: Option> = // `FN` is a function pointer, or a closure // _without_ a captured environment. @@ -563,7 +587,14 @@ macro_rules! impl_traits { { #[allow(non_snake_case)] fn to_raw(self) -> (NonNull, Option>) { - /// This is required for the llvm backend to be able to unwind through this function. + // The `wrap` function is a wrapper around the + // imported function. It manages the argument passed + // to the imported function (in this case, only the + // regular WebAssembly arguments), and it manages the + // trapping. + // + // It is also 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>( func_ctx: &mut vm::FuncCtx $( , $x: <$x as WasmExternType>::Native )* @@ -574,18 +605,29 @@ macro_rules! impl_traits { Trap: TrapEarly, FN: Fn($( $x, )*) -> Trap, { + // Extract `vm::Ctx` from `vm::FuncCtx`. The + // pointer is always non-null. let vmctx = unsafe { func_ctx.vmctx.as_mut() }; + + // Extract `vm::FuncEnv` from `vm::FuncCtx`. let func_env = func_ctx.func_env; let func: &FN = match func_env { + // The imported function is a closure with a + // captured environment. Some(func_env) => unsafe { let func: NonNull = func_env.cast(); &*func.as_ptr() }, + + // The imported function is a regular function + // or a closure without a captured + // environment. None => unsafe { mem::transmute_copy(&()) } }; + // Catch unwind in case of errors. let err = match panic::catch_unwind( panic::AssertUnwindSafe( || { @@ -601,11 +643,15 @@ macro_rules! impl_traits { Err(err) => err, }; + // At this point, there is an error that needs to + // be trapped. unsafe { (&*vmctx.module).runnable_module.do_early_trap(err) } } + // Extract the captured environment of the imported + // function if any. let func_env: Option> = // `FN` is a function pointer, or a closure // _without_ a captured environment. From 0f82cd3c4090f9538c3d81ae3377dc88bffb6cb4 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 4 Nov 2019 21:50:19 +0100 Subject: [PATCH 066/342] doc(runtime-core) Write more documentation. --- lib/runtime-core/src/vm.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index dc92c788f9f..240f71e1cab 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -498,25 +498,33 @@ impl Ctx { } } -/// Used to provide type safety (ish) for passing around function pointers. +/// Represents a function pointer. It is mostly used in the +/// `typed_func` module within the `wrap` functions, to wrap imported +/// functions. #[repr(C)] pub struct Func { _private: [u8; 0], } +/// Represents a function environment pointer, like a captured +/// environment of a closure. It is mostly used in the `typed_func` +/// module within the `wrap` functions, to wrap imported functions. #[repr(C)] pub struct FuncEnv { _private: [u8; 0], } +/// Represents a function context. It is used by imported function +/// only. #[derive(Debug)] #[repr(C)] -pub struct FuncCtx { +pub(crate) struct FuncCtx { pub(crate) vmctx: NonNull, pub(crate) func_env: Option>, } -/// An imported function, which contains the vmctx that owns this function. +/// An imported function is a function pointer associated to a +/// function context. #[derive(Debug, Clone)] #[repr(C)] pub struct ImportedFunc { @@ -524,7 +532,7 @@ pub struct ImportedFunc { pub(crate) func_ctx: NonNull, } -// manually implemented because ImportedFunc contains raw pointers +// Manually implemented because ImportedFunc contains raw pointers // directly; `Func` is marked Send (But `Ctx` actually isn't! (TODO: // review this, shouldn't `Ctx` be Send?)) unsafe impl Send for ImportedFunc {} From 293b71ac54c72858d875a371962d453cefe5f299 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 4 Nov 2019 21:56:36 +0100 Subject: [PATCH 067/342] doc(runtime-core) Write more documentation. --- lib/runtime-core/src/backing.rs | 12 +++++++++--- lib/runtime-core/src/typed_func.rs | 4 ++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/runtime-core/src/backing.rs b/lib/runtime-core/src/backing.rs index c6fffb55329..2493e9d35bc 100644 --- a/lib/runtime-core/src/backing.rs +++ b/lib/runtime-core/src/backing.rs @@ -547,6 +547,7 @@ impl ImportBacking { impl Drop for ImportBacking { fn drop(&mut self) { + // Properly drop the `vm::FuncCtx` in `vm::ImportedFunc`. for (_imported_func_index, imported_func) in (*self.vm_functions).iter_mut() { let _: Box = unsafe { Box::from_raw(imported_func.func_ctx.as_ptr()) }; } @@ -587,12 +588,17 @@ fn import_functions( functions.push(vm::ImportedFunc { func: func.inner(), func_ctx: NonNull::new(Box::into_raw(Box::new(vm::FuncCtx { + // ^^^^^^^^ `vm::FuncCtx` is purposely leaked. + // It is dropped by the specific `Drop` + // implementation of `ImportBacking`. vmctx: NonNull::new(vmctx).expect("`vmctx` must not be null."), func_env: match ctx { Context::External(ctx) => { - NonNull::new(ctx).map(|pointer| { - pointer.cast() // `*mut vm::FuncEnv` was casted to `*mut vm::Ctx` to fit in `Context::External`. Cast it back. - }) + NonNull::new(ctx).map(NonNull::cast) + // ^^^^^^^^^^^^^ + // `*mut vm::FuncEnv` was casted to + // `*mut vm::Ctx` to fit in + // `Context::External`. Cast it back. } Context::Internal => None, }, diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 6bc287bae3b..6d7f79e4ca9 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -725,6 +725,10 @@ where let func = unsafe { FuncPointer::new(self.func.as_ptr()) }; let ctx = match self.func_env { Some(func_env) => Context::External(func_env.cast().as_ptr()), + // ^^^^^^ + // `Context::External` expects a `vm::Ctx`. + // Casting to `vm::FuncCtx` happens in the + // `backing` module. None => Context::Internal, }; let signature = Arc::new(FuncSig::new(Args::types(), Rets::types())); From a9e0e9baebf630b81aa4ca7f9fef759ab35d4973 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 4 Nov 2019 21:59:18 +0100 Subject: [PATCH 068/342] test(runtime-core) Write more documentation. --- lib/runtime-core-tests/tests/imports.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/runtime-core-tests/tests/imports.rs b/lib/runtime-core-tests/tests/imports.rs index bba5050f1ae..cbdc5a38973 100644 --- a/lib/runtime-core-tests/tests/imports.rs +++ b/lib/runtime-core-tests/tests/imports.rs @@ -55,7 +55,14 @@ macro_rules! call_and_assert { }; } +/// The shift that is set in the instance memory. The value is part of +/// the result returned by the imported functions if the memory is +/// read properly. const SHIFT: i32 = 10; + +/// The shift that is captured in the environment of a closure. The +/// value is part of the result returned by the imported function if +/// the closure captures its environment properly. const shift: i32 = 100; fn imported_functions_forms(test: &dyn Fn(&Instance)) { From a4ba429ed0e80b479101ae7a3cd4a1cbf868b509 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 5 Nov 2019 15:07:37 +0100 Subject: [PATCH 069/342] feat(singlepass-backend) Inject `FuncCtx` to the function pointer of an host function. --- lib/singlepass-backend/src/codegen_x64.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index f4411a74ce4..3ee60babf4f 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -554,18 +554,24 @@ impl ModuleCodeGenerator // Emits a tail call trampoline that loads the address of the target import function // from Ctx and jumps to it. + let imported_funcs_addr = vm::Ctx::offset_imported_funcs(); + let imported_func = vm::ImportedFunc::size() as usize * id; + let imported_func_addr = imported_func + vm::ImportedFunc::offset_func() as usize; + let imported_func_ctx_addr = imported_func + vm::ImportedFunc::offset_func_ctx() as usize; + a.emit_mov( Size::S64, - Location::Memory(GPR::RDI, vm::Ctx::offset_imported_funcs() as i32), + Location::Memory(GPR::RDI, imported_funcs_addr as i32), Location::GPR(GPR::RAX), ); a.emit_mov( Size::S64, - Location::Memory( - GPR::RAX, - (vm::ImportedFunc::size() as usize * id + vm::ImportedFunc::offset_func() as usize) - as i32, - ), + Location::Memory(GPR::RAX, imported_func_ctx_addr as i32), + Location::GPR(GPR::RDI), + ); + a.emit_mov( + Size::S64, + Location::Memory(GPR::RAX, imported_func_addr as i32), Location::GPR(GPR::RAX), ); a.emit_jmp_location(Location::GPR(GPR::RAX)); From c4c88f8af55a9faa3b47e409e2d0779ab97b2c8d Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 6 Nov 2019 13:58:49 +0100 Subject: [PATCH 070/342] fix(runtime-core) Remove undefined behavior with `mem::transmute`. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the `wrap` functions, we use `std::mem::transmute(&())` to get the pointer to the value “around” `wrap` (`Fn` has a method `to_raw` which declares a `wrap` function, which uses `transmute` to retrieve `Fn`). This is an undefined behavior. It was working until the `FuncCtx` is introduced. Since then, the undefined behavior was causing an error with the Singlepass backend. This patch stores the pointer to `Fn` in `func_env`, so that the pointer to the user-defined host function is always predictable. --- lib/runtime-core/src/typed_func.rs | 28 ++++++++++++++-------------- lib/runtime-core/src/vm.rs | 8 +++++++- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 6d7f79e4ca9..9c798460d35 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -517,18 +517,18 @@ macro_rules! impl_traits { let func_env = func_ctx.func_env; let func: &FN = match func_env { - // The imported function is a closure with a - // captured environment. + // The imported function is a regular + // function, a closure without a captured + // environmet, or a closure with a captured + // environment. Some(func_env) => unsafe { let func: NonNull = func_env.cast(); &*func.as_ptr() }, - // The imported function is a regular function - // or a closure without a captured - // environment. - None => unsafe { mem::transmute_copy(&()) } + // This branch is supposed to be unreachable. + None => unreachable!() }; // Catch unwind in case of errors. @@ -563,7 +563,7 @@ macro_rules! impl_traits { // `FN` is a function pointer, or a closure // _without_ a captured environment. if mem::size_of::() == 0 { - None + NonNull::new(&self as *const _ as *mut vm::FuncEnv) } // `FN` is a closure _with_ a captured // environment. Grab it. @@ -613,18 +613,18 @@ macro_rules! impl_traits { let func_env = func_ctx.func_env; let func: &FN = match func_env { - // The imported function is a closure with a - // captured environment. + // The imported function is a regular + // function, a closure without a captured + // environmet, or a closure with a captured + // environment. Some(func_env) => unsafe { let func: NonNull = func_env.cast(); &*func.as_ptr() }, - // The imported function is a regular function - // or a closure without a captured - // environment. - None => unsafe { mem::transmute_copy(&()) } + // This branch is supposed to be unreachable. + None => unreachable!() }; // Catch unwind in case of errors. @@ -656,7 +656,7 @@ macro_rules! impl_traits { // `FN` is a function pointer, or a closure // _without_ a captured environment. if mem::size_of::() == 0 { - None + NonNull::new(&self as *const _ as *mut vm::FuncEnv) } // `FN` is a closure _with_ a captured // environment. Grab it. diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index 240f71e1cab..1c9a8b7add4 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -514,12 +514,18 @@ pub struct FuncEnv { _private: [u8; 0], } -/// Represents a function context. It is used by imported function +/// Represents a function context. It is used by imported functions /// only. #[derive(Debug)] #[repr(C)] pub(crate) struct FuncCtx { + /// The `Ctx` pointer. pub(crate) vmctx: NonNull, + + /// A pointer to the function environment. It is used by imported + /// functions only to store the pointer to the real host function, + /// whether it is a regular function, or a closure with or without + /// a captured environment. pub(crate) func_env: Option>, } From 5ccaf12b2a2217de3c079aa8409e4970b989b780 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 6 Nov 2019 14:23:26 +0100 Subject: [PATCH 071/342] doc(runtime-core) Fix inline documentations. --- lib/runtime-core/src/typed_func.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 9c798460d35..8c6a7826d86 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -519,7 +519,7 @@ macro_rules! impl_traits { let func: &FN = match func_env { // The imported function is a regular // function, a closure without a captured - // environmet, or a closure with a captured + // environment, or a closure with a captured // environment. Some(func_env) => unsafe { let func: NonNull = func_env.cast(); @@ -566,7 +566,7 @@ macro_rules! impl_traits { NonNull::new(&self as *const _ as *mut vm::FuncEnv) } // `FN` is a closure _with_ a captured - // environment. Grab it. + // environment. else { NonNull::new(Box::into_raw(Box::new(self))).map(NonNull::cast) }; @@ -615,7 +615,7 @@ macro_rules! impl_traits { let func: &FN = match func_env { // The imported function is a regular // function, a closure without a captured - // environmet, or a closure with a captured + // environment, or a closure with a captured // environment. Some(func_env) => unsafe { let func: NonNull = func_env.cast(); @@ -659,7 +659,7 @@ macro_rules! impl_traits { NonNull::new(&self as *const _ as *mut vm::FuncEnv) } // `FN` is a closure _with_ a captured - // environment. Grab it. + // environment. else { NonNull::new(Box::into_raw(Box::new(self))).map(NonNull::cast) }; From 6f84a6f15be9feff42abdd4294fecd1b1c878475 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 6 Nov 2019 14:23:45 +0100 Subject: [PATCH 072/342] test(runtime-core) Remove a warning in tests. --- lib/runtime-core-tests/tests/imports.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/runtime-core-tests/tests/imports.rs b/lib/runtime-core-tests/tests/imports.rs index cbdc5a38973..6b7223c6735 100644 --- a/lib/runtime-core-tests/tests/imports.rs +++ b/lib/runtime-core-tests/tests/imports.rs @@ -63,6 +63,7 @@ const SHIFT: i32 = 10; /// The shift that is captured in the environment of a closure. The /// value is part of the result returned by the imported function if /// the closure captures its environment properly. +#[allow(non_upper_case_globals)] const shift: i32 = 100; fn imported_functions_forms(test: &dyn Fn(&Instance)) { From ac8aece380eebcc7b1aa02b84d9ea3a7e24fe319 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 6 Nov 2019 14:57:10 +0100 Subject: [PATCH 073/342] doc(changelog) Add #915, #917 and #925. --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index afe906514e8..f09f738dc31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## **[Unreleased]** +- [#925](https://github.com/wasmerio/wasmer/pull/925) Host functions can be closures with a captured environment. +- [#917](https://github.com/wasmerio/wasmer/pull/917) Host functions (aka imported functions) may not have `&mut vm::Ctx` as first argument, i.e. the presence of the `&mut vm::Ctx` argument is optional. +- [#915](https://github.com/wasmerio/wasmer/pull/915) All backends share the same definition of `Trampoline` (defined in `wasmer-runtime-core`). - [#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 6135a004a4cebab0bd2aa50d8f1eb3d8624b46df Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 7 Nov 2019 01:11:25 +0800 Subject: [PATCH 074/342] Add itruncf/fconverti fast path. --- lib/singlepass-backend/src/codegen_x64.rs | 1011 ++++++++++++----- lib/singlepass-backend/src/emitter_x64.rs | 20 + .../src/translator_aarch64.rs | 167 ++- 3 files changed, 841 insertions(+), 357 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 20c9a0c2155..5afa0f92832 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -3277,24 +3277,48 @@ impl FunctionCodeGenerator for X64FunctionCode { false, )[0]; self.value_stack.push(ret); - let tmp_out = self.machine.acquire_temp_gpr().unwrap(); - let tmp_in = self.machine.acquire_temp_xmm().unwrap(); - Self::emit_relaxed_binop( - a, - &mut self.machine, - Assembler::emit_mov, - Size::S32, - loc, - Location::XMM(tmp_in), - ); - Self::emit_f32_int_conv_check(a, &mut self.machine, tmp_in, -1.0, 4294967296.0); + if a.arch_has_itruncf() { + let tmp_out = self.machine.acquire_temp_gpr().unwrap(); + let tmp_in = self.machine.acquire_temp_xmm().unwrap(); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + loc, + Location::XMM(tmp_in), + ); + a.arch_emit_i32_trunc_uf32(tmp_in, tmp_out); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + Location::GPR(tmp_out), + ret, + ); + self.machine.release_temp_xmm(tmp_in); + self.machine.release_temp_gpr(tmp_out); + } else { + let tmp_out = self.machine.acquire_temp_gpr().unwrap(); + let tmp_in = self.machine.acquire_temp_xmm().unwrap(); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + loc, + Location::XMM(tmp_in), + ); + Self::emit_f32_int_conv_check(a, &mut self.machine, tmp_in, -1.0, 4294967296.0); - a.emit_cvttss2si_64(XMMOrMemory::XMM(tmp_in), tmp_out); - a.emit_mov(Size::S32, Location::GPR(tmp_out), ret); + a.emit_cvttss2si_64(XMMOrMemory::XMM(tmp_in), tmp_out); + a.emit_mov(Size::S32, Location::GPR(tmp_out), ret); - self.machine.release_temp_xmm(tmp_in); - self.machine.release_temp_gpr(tmp_out); + self.machine.release_temp_xmm(tmp_in); + self.machine.release_temp_gpr(tmp_out); + } } Operator::I32TruncSF32 => { @@ -3306,30 +3330,55 @@ impl FunctionCodeGenerator for X64FunctionCode { false, )[0]; self.value_stack.push(ret); - let tmp_out = self.machine.acquire_temp_gpr().unwrap(); - let tmp_in = self.machine.acquire_temp_xmm().unwrap(); - Self::emit_relaxed_binop( - a, - &mut self.machine, - Assembler::emit_mov, - Size::S32, - loc, - Location::XMM(tmp_in), - ); - Self::emit_f32_int_conv_check( - a, - &mut self.machine, - tmp_in, - -2147483904.0, - 2147483648.0, - ); + if a.arch_has_itruncf() { + let tmp_out = self.machine.acquire_temp_gpr().unwrap(); + let tmp_in = self.machine.acquire_temp_xmm().unwrap(); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + loc, + Location::XMM(tmp_in), + ); + a.arch_emit_i32_trunc_sf32(tmp_in, tmp_out); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + Location::GPR(tmp_out), + ret, + ); + self.machine.release_temp_xmm(tmp_in); + self.machine.release_temp_gpr(tmp_out); + } else { + let tmp_out = self.machine.acquire_temp_gpr().unwrap(); + let tmp_in = self.machine.acquire_temp_xmm().unwrap(); + + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + loc, + Location::XMM(tmp_in), + ); + Self::emit_f32_int_conv_check( + a, + &mut self.machine, + tmp_in, + -2147483904.0, + 2147483648.0, + ); - a.emit_cvttss2si_32(XMMOrMemory::XMM(tmp_in), tmp_out); - a.emit_mov(Size::S32, Location::GPR(tmp_out), ret); + a.emit_cvttss2si_32(XMMOrMemory::XMM(tmp_in), tmp_out); + a.emit_mov(Size::S32, Location::GPR(tmp_out), ret); - self.machine.release_temp_xmm(tmp_in); - self.machine.release_temp_gpr(tmp_out); + self.machine.release_temp_xmm(tmp_in); + self.machine.release_temp_gpr(tmp_out); + } } Operator::I64TruncSF32 => { @@ -3341,47 +3390,57 @@ impl FunctionCodeGenerator for X64FunctionCode { false, )[0]; self.value_stack.push(ret); - let tmp_out = self.machine.acquire_temp_gpr().unwrap(); - let tmp_in = self.machine.acquire_temp_xmm().unwrap(); - Self::emit_relaxed_binop( - a, - &mut self.machine, - Assembler::emit_mov, - Size::S32, - loc, - Location::XMM(tmp_in), - ); - Self::emit_f32_int_conv_check( - a, - &mut self.machine, - tmp_in, - -9223373136366403584.0, - 9223372036854775808.0, - ); - a.emit_cvttss2si_64(XMMOrMemory::XMM(tmp_in), tmp_out); - a.emit_mov(Size::S64, Location::GPR(tmp_out), ret); + if a.arch_has_itruncf() { + let tmp_out = self.machine.acquire_temp_gpr().unwrap(); + let tmp_in = self.machine.acquire_temp_xmm().unwrap(); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + loc, + Location::XMM(tmp_in), + ); + a.arch_emit_i64_trunc_sf32(tmp_in, tmp_out); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S64, + Location::GPR(tmp_out), + ret, + ); + self.machine.release_temp_xmm(tmp_in); + self.machine.release_temp_gpr(tmp_out); + } else { + let tmp_out = self.machine.acquire_temp_gpr().unwrap(); + let tmp_in = self.machine.acquire_temp_xmm().unwrap(); + + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + loc, + Location::XMM(tmp_in), + ); + Self::emit_f32_int_conv_check( + a, + &mut self.machine, + tmp_in, + -9223373136366403584.0, + 9223372036854775808.0, + ); + a.emit_cvttss2si_64(XMMOrMemory::XMM(tmp_in), tmp_out); + a.emit_mov(Size::S64, Location::GPR(tmp_out), ret); - self.machine.release_temp_xmm(tmp_in); - self.machine.release_temp_gpr(tmp_out); + self.machine.release_temp_xmm(tmp_in); + self.machine.release_temp_gpr(tmp_out); + } } Operator::I64TruncUF32 => { - /* - ; movq xmm5, r15 - ; mov r15d, 1593835520u32 as i32 //float 9.22337203E+18 - ; movd xmm1, r15d - ; movd xmm2, Rd(reg as u8) - ; movd xmm3, Rd(reg as u8) - ; subss xmm2, xmm1 - ; cvttss2si Rq(reg as u8), xmm2 - ; mov r15, QWORD 0x8000000000000000u64 as i64 - ; xor r15, Rq(reg as u8) - ; cvttss2si Rq(reg as u8), xmm3 - ; ucomiss xmm3, xmm1 - ; cmovae Rq(reg as u8), r15 - ; movq r15, xmm5 - */ let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let ret = self.machine.acquire_locations( @@ -3390,54 +3449,79 @@ impl FunctionCodeGenerator for X64FunctionCode { false, )[0]; self.value_stack.push(ret); - let tmp_out = self.machine.acquire_temp_gpr().unwrap(); - let tmp_in = self.machine.acquire_temp_xmm().unwrap(); // xmm2 - Self::emit_relaxed_binop( - a, - &mut self.machine, - Assembler::emit_mov, - Size::S32, - loc, - Location::XMM(tmp_in), - ); - Self::emit_f32_int_conv_check( - a, - &mut self.machine, - tmp_in, - -1.0, - 18446744073709551616.0, - ); + if a.arch_has_itruncf() { + let tmp_out = self.machine.acquire_temp_gpr().unwrap(); + let tmp_in = self.machine.acquire_temp_xmm().unwrap(); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + loc, + Location::XMM(tmp_in), + ); + a.arch_emit_i64_trunc_uf32(tmp_in, tmp_out); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S64, + Location::GPR(tmp_out), + ret, + ); + self.machine.release_temp_xmm(tmp_in); + self.machine.release_temp_gpr(tmp_out); + } else { + let tmp_out = self.machine.acquire_temp_gpr().unwrap(); + let tmp_in = self.machine.acquire_temp_xmm().unwrap(); // xmm2 - let tmp = self.machine.acquire_temp_gpr().unwrap(); // r15 - let tmp_x1 = self.machine.acquire_temp_xmm().unwrap(); // xmm1 - let tmp_x2 = self.machine.acquire_temp_xmm().unwrap(); // xmm3 + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + loc, + Location::XMM(tmp_in), + ); + Self::emit_f32_int_conv_check( + a, + &mut self.machine, + tmp_in, + -1.0, + 18446744073709551616.0, + ); - a.emit_mov( - Size::S32, - Location::Imm32(1593835520u32), - Location::GPR(tmp), - ); //float 9.22337203E+18 - a.emit_mov(Size::S32, Location::GPR(tmp), Location::XMM(tmp_x1)); - a.emit_mov(Size::S32, Location::XMM(tmp_in), Location::XMM(tmp_x2)); - a.emit_vsubss(tmp_in, XMMOrMemory::XMM(tmp_x1), tmp_in); - a.emit_cvttss2si_64(XMMOrMemory::XMM(tmp_in), tmp_out); - a.emit_mov( - Size::S64, - Location::Imm64(0x8000000000000000u64), - Location::GPR(tmp), - ); - a.emit_xor(Size::S64, Location::GPR(tmp_out), Location::GPR(tmp)); - a.emit_cvttss2si_64(XMMOrMemory::XMM(tmp_x2), tmp_out); - a.emit_ucomiss(XMMOrMemory::XMM(tmp_x1), tmp_x2); - a.emit_cmovae_gpr_64(tmp, tmp_out); - a.emit_mov(Size::S64, Location::GPR(tmp_out), ret); - - self.machine.release_temp_xmm(tmp_x2); - self.machine.release_temp_xmm(tmp_x1); - self.machine.release_temp_gpr(tmp); - self.machine.release_temp_xmm(tmp_in); - self.machine.release_temp_gpr(tmp_out); + let tmp = self.machine.acquire_temp_gpr().unwrap(); // r15 + let tmp_x1 = self.machine.acquire_temp_xmm().unwrap(); // xmm1 + let tmp_x2 = self.machine.acquire_temp_xmm().unwrap(); // xmm3 + + a.emit_mov( + Size::S32, + Location::Imm32(1593835520u32), + Location::GPR(tmp), + ); //float 9.22337203E+18 + a.emit_mov(Size::S32, Location::GPR(tmp), Location::XMM(tmp_x1)); + a.emit_mov(Size::S32, Location::XMM(tmp_in), Location::XMM(tmp_x2)); + a.emit_vsubss(tmp_in, XMMOrMemory::XMM(tmp_x1), tmp_in); + a.emit_cvttss2si_64(XMMOrMemory::XMM(tmp_in), tmp_out); + a.emit_mov( + Size::S64, + Location::Imm64(0x8000000000000000u64), + Location::GPR(tmp), + ); + a.emit_xor(Size::S64, Location::GPR(tmp_out), Location::GPR(tmp)); + a.emit_cvttss2si_64(XMMOrMemory::XMM(tmp_x2), tmp_out); + a.emit_ucomiss(XMMOrMemory::XMM(tmp_x1), tmp_x2); + a.emit_cmovae_gpr_64(tmp, tmp_out); + a.emit_mov(Size::S64, Location::GPR(tmp_out), ret); + + self.machine.release_temp_xmm(tmp_x2); + self.machine.release_temp_xmm(tmp_x1); + self.machine.release_temp_gpr(tmp); + self.machine.release_temp_xmm(tmp_in); + self.machine.release_temp_gpr(tmp_out); + } } Operator::I32TruncUF64 => { @@ -3449,24 +3533,49 @@ impl FunctionCodeGenerator for X64FunctionCode { false, )[0]; self.value_stack.push(ret); - let tmp_out = self.machine.acquire_temp_gpr().unwrap(); - let tmp_in = self.machine.acquire_temp_xmm().unwrap(); - Self::emit_relaxed_binop( - a, - &mut self.machine, - Assembler::emit_mov, - Size::S64, - loc, - Location::XMM(tmp_in), - ); - Self::emit_f64_int_conv_check(a, &mut self.machine, tmp_in, -1.0, 4294967296.0); + if a.arch_has_itruncf() { + let tmp_out = self.machine.acquire_temp_gpr().unwrap(); + let tmp_in = self.machine.acquire_temp_xmm().unwrap(); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S64, + loc, + Location::XMM(tmp_in), + ); + a.arch_emit_i32_trunc_uf64(tmp_in, tmp_out); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + Location::GPR(tmp_out), + ret, + ); + self.machine.release_temp_xmm(tmp_in); + self.machine.release_temp_gpr(tmp_out); + } else { + let tmp_out = self.machine.acquire_temp_gpr().unwrap(); + let tmp_in = self.machine.acquire_temp_xmm().unwrap(); + + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S64, + loc, + Location::XMM(tmp_in), + ); + Self::emit_f64_int_conv_check(a, &mut self.machine, tmp_in, -1.0, 4294967296.0); - a.emit_cvttsd2si_64(XMMOrMemory::XMM(tmp_in), tmp_out); - a.emit_mov(Size::S32, Location::GPR(tmp_out), ret); + a.emit_cvttsd2si_64(XMMOrMemory::XMM(tmp_in), tmp_out); + a.emit_mov(Size::S32, Location::GPR(tmp_out), ret); - self.machine.release_temp_xmm(tmp_in); - self.machine.release_temp_gpr(tmp_out); + self.machine.release_temp_xmm(tmp_in); + self.machine.release_temp_gpr(tmp_out); + } } Operator::I32TruncSF64 => { @@ -3478,35 +3587,60 @@ impl FunctionCodeGenerator for X64FunctionCode { false, )[0]; self.value_stack.push(ret); - let tmp_out = self.machine.acquire_temp_gpr().unwrap(); - let tmp_in = self.machine.acquire_temp_xmm().unwrap(); - - let real_in = match loc { - Location::Imm32(_) | Location::Imm64(_) => { - a.emit_mov(Size::S64, loc, Location::GPR(tmp_out)); - a.emit_mov(Size::S64, Location::GPR(tmp_out), Location::XMM(tmp_in)); - tmp_in - } - Location::XMM(x) => x, - _ => { - a.emit_mov(Size::S64, loc, Location::XMM(tmp_in)); - tmp_in - } - }; - Self::emit_f64_int_conv_check( - a, - &mut self.machine, - real_in, - -2147483649.0, - 2147483648.0, - ); + if a.arch_has_itruncf() { + let tmp_out = self.machine.acquire_temp_gpr().unwrap(); + let tmp_in = self.machine.acquire_temp_xmm().unwrap(); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S64, + loc, + Location::XMM(tmp_in), + ); + a.arch_emit_i32_trunc_sf64(tmp_in, tmp_out); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + Location::GPR(tmp_out), + ret, + ); + self.machine.release_temp_xmm(tmp_in); + self.machine.release_temp_gpr(tmp_out); + } else { + let tmp_out = self.machine.acquire_temp_gpr().unwrap(); + let tmp_in = self.machine.acquire_temp_xmm().unwrap(); + + let real_in = match loc { + Location::Imm32(_) | Location::Imm64(_) => { + a.emit_mov(Size::S64, loc, Location::GPR(tmp_out)); + a.emit_mov(Size::S64, Location::GPR(tmp_out), Location::XMM(tmp_in)); + tmp_in + } + Location::XMM(x) => x, + _ => { + a.emit_mov(Size::S64, loc, Location::XMM(tmp_in)); + tmp_in + } + }; - a.emit_cvttsd2si_32(XMMOrMemory::XMM(real_in), tmp_out); - a.emit_mov(Size::S32, Location::GPR(tmp_out), ret); + Self::emit_f64_int_conv_check( + a, + &mut self.machine, + real_in, + -2147483649.0, + 2147483648.0, + ); + + a.emit_cvttsd2si_32(XMMOrMemory::XMM(real_in), tmp_out); + a.emit_mov(Size::S32, Location::GPR(tmp_out), ret); - self.machine.release_temp_xmm(tmp_in); - self.machine.release_temp_gpr(tmp_out); + self.machine.release_temp_xmm(tmp_in); + self.machine.release_temp_gpr(tmp_out); + } } Operator::I64TruncSF64 => { @@ -3518,30 +3652,55 @@ impl FunctionCodeGenerator for X64FunctionCode { false, )[0]; self.value_stack.push(ret); - let tmp_out = self.machine.acquire_temp_gpr().unwrap(); - let tmp_in = self.machine.acquire_temp_xmm().unwrap(); - Self::emit_relaxed_binop( - a, - &mut self.machine, - Assembler::emit_mov, - Size::S64, - loc, - Location::XMM(tmp_in), - ); - Self::emit_f64_int_conv_check( - a, - &mut self.machine, - tmp_in, - -9223372036854777856.0, - 9223372036854775808.0, - ); + if a.arch_has_itruncf() { + let tmp_out = self.machine.acquire_temp_gpr().unwrap(); + let tmp_in = self.machine.acquire_temp_xmm().unwrap(); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S64, + loc, + Location::XMM(tmp_in), + ); + a.arch_emit_i64_trunc_sf64(tmp_in, tmp_out); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S64, + Location::GPR(tmp_out), + ret, + ); + self.machine.release_temp_xmm(tmp_in); + self.machine.release_temp_gpr(tmp_out); + } else { + let tmp_out = self.machine.acquire_temp_gpr().unwrap(); + let tmp_in = self.machine.acquire_temp_xmm().unwrap(); + + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S64, + loc, + Location::XMM(tmp_in), + ); + Self::emit_f64_int_conv_check( + a, + &mut self.machine, + tmp_in, + -9223372036854777856.0, + 9223372036854775808.0, + ); - a.emit_cvttsd2si_64(XMMOrMemory::XMM(tmp_in), tmp_out); - a.emit_mov(Size::S64, Location::GPR(tmp_out), ret); + a.emit_cvttsd2si_64(XMMOrMemory::XMM(tmp_in), tmp_out); + a.emit_mov(Size::S64, Location::GPR(tmp_out), ret); - self.machine.release_temp_xmm(tmp_in); - self.machine.release_temp_gpr(tmp_out); + self.machine.release_temp_xmm(tmp_in); + self.machine.release_temp_gpr(tmp_out); + } } Operator::I64TruncUF64 => { @@ -3553,54 +3712,79 @@ impl FunctionCodeGenerator for X64FunctionCode { false, )[0]; self.value_stack.push(ret); - let tmp_out = self.machine.acquire_temp_gpr().unwrap(); - let tmp_in = self.machine.acquire_temp_xmm().unwrap(); // xmm2 - Self::emit_relaxed_binop( - a, - &mut self.machine, - Assembler::emit_mov, - Size::S64, - loc, - Location::XMM(tmp_in), - ); - Self::emit_f64_int_conv_check( - a, - &mut self.machine, - tmp_in, - -1.0, - 18446744073709551616.0, - ); + if a.arch_has_itruncf() { + let tmp_out = self.machine.acquire_temp_gpr().unwrap(); + let tmp_in = self.machine.acquire_temp_xmm().unwrap(); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S64, + loc, + Location::XMM(tmp_in), + ); + a.arch_emit_i64_trunc_uf64(tmp_in, tmp_out); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S64, + Location::GPR(tmp_out), + ret, + ); + self.machine.release_temp_xmm(tmp_in); + self.machine.release_temp_gpr(tmp_out); + } else { + let tmp_out = self.machine.acquire_temp_gpr().unwrap(); + let tmp_in = self.machine.acquire_temp_xmm().unwrap(); // xmm2 - let tmp = self.machine.acquire_temp_gpr().unwrap(); // r15 - let tmp_x1 = self.machine.acquire_temp_xmm().unwrap(); // xmm1 - let tmp_x2 = self.machine.acquire_temp_xmm().unwrap(); // xmm3 + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S64, + loc, + Location::XMM(tmp_in), + ); + Self::emit_f64_int_conv_check( + a, + &mut self.machine, + tmp_in, + -1.0, + 18446744073709551616.0, + ); - a.emit_mov( - Size::S64, - Location::Imm64(4890909195324358656u64), - Location::GPR(tmp), - ); //double 9.2233720368547758E+18 - a.emit_mov(Size::S64, Location::GPR(tmp), Location::XMM(tmp_x1)); - a.emit_mov(Size::S64, Location::XMM(tmp_in), Location::XMM(tmp_x2)); - a.emit_vsubsd(tmp_in, XMMOrMemory::XMM(tmp_x1), tmp_in); - a.emit_cvttsd2si_64(XMMOrMemory::XMM(tmp_in), tmp_out); - a.emit_mov( - Size::S64, - Location::Imm64(0x8000000000000000u64), - Location::GPR(tmp), - ); - a.emit_xor(Size::S64, Location::GPR(tmp_out), Location::GPR(tmp)); - a.emit_cvttsd2si_64(XMMOrMemory::XMM(tmp_x2), tmp_out); - a.emit_ucomisd(XMMOrMemory::XMM(tmp_x1), tmp_x2); - a.emit_cmovae_gpr_64(tmp, tmp_out); - a.emit_mov(Size::S64, Location::GPR(tmp_out), ret); - - self.machine.release_temp_xmm(tmp_x2); - self.machine.release_temp_xmm(tmp_x1); - self.machine.release_temp_gpr(tmp); - self.machine.release_temp_xmm(tmp_in); - self.machine.release_temp_gpr(tmp_out); + let tmp = self.machine.acquire_temp_gpr().unwrap(); // r15 + let tmp_x1 = self.machine.acquire_temp_xmm().unwrap(); // xmm1 + let tmp_x2 = self.machine.acquire_temp_xmm().unwrap(); // xmm3 + + a.emit_mov( + Size::S64, + Location::Imm64(4890909195324358656u64), + Location::GPR(tmp), + ); //double 9.2233720368547758E+18 + a.emit_mov(Size::S64, Location::GPR(tmp), Location::XMM(tmp_x1)); + a.emit_mov(Size::S64, Location::XMM(tmp_in), Location::XMM(tmp_x2)); + a.emit_vsubsd(tmp_in, XMMOrMemory::XMM(tmp_x1), tmp_in); + a.emit_cvttsd2si_64(XMMOrMemory::XMM(tmp_in), tmp_out); + a.emit_mov( + Size::S64, + Location::Imm64(0x8000000000000000u64), + Location::GPR(tmp), + ); + a.emit_xor(Size::S64, Location::GPR(tmp_out), Location::GPR(tmp)); + a.emit_cvttsd2si_64(XMMOrMemory::XMM(tmp_x2), tmp_out); + a.emit_ucomisd(XMMOrMemory::XMM(tmp_x1), tmp_x2); + a.emit_cmovae_gpr_64(tmp, tmp_out); + a.emit_mov(Size::S64, Location::GPR(tmp_out), ret); + + self.machine.release_temp_xmm(tmp_x2); + self.machine.release_temp_xmm(tmp_x1); + self.machine.release_temp_gpr(tmp); + self.machine.release_temp_xmm(tmp_in); + self.machine.release_temp_gpr(tmp_out); + } } Operator::F32ConvertSI32 => { @@ -3612,15 +3796,40 @@ impl FunctionCodeGenerator for X64FunctionCode { false, )[0]; self.value_stack.push(ret); - let tmp_out = self.machine.acquire_temp_xmm().unwrap(); - let tmp_in = self.machine.acquire_temp_gpr().unwrap(); - a.emit_mov(Size::S32, loc, Location::GPR(tmp_in)); - a.emit_vcvtsi2ss_32(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out); - a.emit_mov(Size::S32, Location::XMM(tmp_out), ret); + if a.arch_has_fconverti() { + let tmp_out = self.machine.acquire_temp_xmm().unwrap(); + let tmp_in = self.machine.acquire_temp_gpr().unwrap(); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + loc, + Location::GPR(tmp_in), + ); + a.arch_emit_f32_convert_si32(tmp_in, tmp_out); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + Location::XMM(tmp_out), + ret, + ); + self.machine.release_temp_gpr(tmp_in); + self.machine.release_temp_xmm(tmp_out); + } else { + let tmp_out = self.machine.acquire_temp_xmm().unwrap(); + let tmp_in = self.machine.acquire_temp_gpr().unwrap(); + + a.emit_mov(Size::S32, loc, Location::GPR(tmp_in)); + a.emit_vcvtsi2ss_32(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out); + a.emit_mov(Size::S32, Location::XMM(tmp_out), ret); - self.machine.release_temp_gpr(tmp_in); - self.machine.release_temp_xmm(tmp_out); + self.machine.release_temp_gpr(tmp_in); + self.machine.release_temp_xmm(tmp_out); + } } Operator::F32ConvertUI32 => { let loc = @@ -3631,15 +3840,39 @@ impl FunctionCodeGenerator for X64FunctionCode { false, )[0]; self.value_stack.push(ret); - let tmp_out = self.machine.acquire_temp_xmm().unwrap(); - let tmp_in = self.machine.acquire_temp_gpr().unwrap(); + if a.arch_has_fconverti() { + let tmp_out = self.machine.acquire_temp_xmm().unwrap(); + let tmp_in = self.machine.acquire_temp_gpr().unwrap(); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + loc, + Location::GPR(tmp_in), + ); + a.arch_emit_f32_convert_ui32(tmp_in, tmp_out); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + Location::XMM(tmp_out), + ret, + ); + self.machine.release_temp_gpr(tmp_in); + self.machine.release_temp_xmm(tmp_out); + } else { + let tmp_out = self.machine.acquire_temp_xmm().unwrap(); + let tmp_in = self.machine.acquire_temp_gpr().unwrap(); - a.emit_mov(Size::S32, loc, Location::GPR(tmp_in)); - a.emit_vcvtsi2ss_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out); - a.emit_mov(Size::S32, Location::XMM(tmp_out), ret); + a.emit_mov(Size::S32, loc, Location::GPR(tmp_in)); + a.emit_vcvtsi2ss_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out); + a.emit_mov(Size::S32, Location::XMM(tmp_out), ret); - self.machine.release_temp_gpr(tmp_in); - self.machine.release_temp_xmm(tmp_out); + self.machine.release_temp_gpr(tmp_in); + self.machine.release_temp_xmm(tmp_out); + } } Operator::F32ConvertSI64 => { let loc = @@ -3650,15 +3883,39 @@ impl FunctionCodeGenerator for X64FunctionCode { false, )[0]; self.value_stack.push(ret); - let tmp_out = self.machine.acquire_temp_xmm().unwrap(); - let tmp_in = self.machine.acquire_temp_gpr().unwrap(); + if a.arch_has_fconverti() { + let tmp_out = self.machine.acquire_temp_xmm().unwrap(); + let tmp_in = self.machine.acquire_temp_gpr().unwrap(); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S64, + loc, + Location::GPR(tmp_in), + ); + a.arch_emit_f32_convert_si64(tmp_in, tmp_out); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + Location::XMM(tmp_out), + ret, + ); + self.machine.release_temp_gpr(tmp_in); + self.machine.release_temp_xmm(tmp_out); + } else { + let tmp_out = self.machine.acquire_temp_xmm().unwrap(); + let tmp_in = self.machine.acquire_temp_gpr().unwrap(); - a.emit_mov(Size::S64, loc, Location::GPR(tmp_in)); - a.emit_vcvtsi2ss_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out); - a.emit_mov(Size::S32, Location::XMM(tmp_out), ret); + a.emit_mov(Size::S64, loc, Location::GPR(tmp_in)); + a.emit_vcvtsi2ss_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out); + a.emit_mov(Size::S32, Location::XMM(tmp_out), ret); - self.machine.release_temp_gpr(tmp_in); - self.machine.release_temp_xmm(tmp_out); + self.machine.release_temp_gpr(tmp_in); + self.machine.release_temp_xmm(tmp_out); + } } Operator::F32ConvertUI64 => { let loc = @@ -3669,31 +3926,55 @@ impl FunctionCodeGenerator for X64FunctionCode { false, )[0]; self.value_stack.push(ret); - let tmp_out = self.machine.acquire_temp_xmm().unwrap(); - let tmp_in = self.machine.acquire_temp_gpr().unwrap(); - let tmp = self.machine.acquire_temp_gpr().unwrap(); - - let do_convert = a.get_label(); - let end_convert = a.get_label(); - - a.emit_mov(Size::S64, loc, Location::GPR(tmp_in)); - a.emit_test_gpr_64(tmp_in); - a.emit_jmp(Condition::Signed, do_convert); - a.emit_vcvtsi2ss_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out); - a.emit_jmp(Condition::None, end_convert); - a.emit_label(do_convert); - a.emit_mov(Size::S64, Location::GPR(tmp_in), Location::GPR(tmp)); - a.emit_and(Size::S64, Location::Imm32(1), Location::GPR(tmp)); - a.emit_shr(Size::S64, Location::Imm8(1), Location::GPR(tmp_in)); - a.emit_or(Size::S64, Location::GPR(tmp), Location::GPR(tmp_in)); - a.emit_vcvtsi2ss_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out); - a.emit_vaddss(tmp_out, XMMOrMemory::XMM(tmp_out), tmp_out); - a.emit_label(end_convert); - a.emit_mov(Size::S32, Location::XMM(tmp_out), ret); - - self.machine.release_temp_gpr(tmp); - self.machine.release_temp_gpr(tmp_in); - self.machine.release_temp_xmm(tmp_out); + if a.arch_has_fconverti() { + let tmp_out = self.machine.acquire_temp_xmm().unwrap(); + let tmp_in = self.machine.acquire_temp_gpr().unwrap(); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S64, + loc, + Location::GPR(tmp_in), + ); + a.arch_emit_f32_convert_ui64(tmp_in, tmp_out); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + Location::XMM(tmp_out), + ret, + ); + self.machine.release_temp_gpr(tmp_in); + self.machine.release_temp_xmm(tmp_out); + } else { + let tmp_out = self.machine.acquire_temp_xmm().unwrap(); + let tmp_in = self.machine.acquire_temp_gpr().unwrap(); + let tmp = self.machine.acquire_temp_gpr().unwrap(); + + let do_convert = a.get_label(); + let end_convert = a.get_label(); + + a.emit_mov(Size::S64, loc, Location::GPR(tmp_in)); + a.emit_test_gpr_64(tmp_in); + a.emit_jmp(Condition::Signed, do_convert); + a.emit_vcvtsi2ss_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out); + a.emit_jmp(Condition::None, end_convert); + a.emit_label(do_convert); + a.emit_mov(Size::S64, Location::GPR(tmp_in), Location::GPR(tmp)); + a.emit_and(Size::S64, Location::Imm32(1), Location::GPR(tmp)); + a.emit_shr(Size::S64, Location::Imm8(1), Location::GPR(tmp_in)); + a.emit_or(Size::S64, Location::GPR(tmp), Location::GPR(tmp_in)); + a.emit_vcvtsi2ss_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out); + a.emit_vaddss(tmp_out, XMMOrMemory::XMM(tmp_out), tmp_out); + a.emit_label(end_convert); + a.emit_mov(Size::S32, Location::XMM(tmp_out), ret); + + self.machine.release_temp_gpr(tmp); + self.machine.release_temp_gpr(tmp_in); + self.machine.release_temp_xmm(tmp_out); + } } Operator::F64ConvertSI32 => { @@ -3705,15 +3986,40 @@ impl FunctionCodeGenerator for X64FunctionCode { false, )[0]; self.value_stack.push(ret); - let tmp_out = self.machine.acquire_temp_xmm().unwrap(); - let tmp_in = self.machine.acquire_temp_gpr().unwrap(); - a.emit_mov(Size::S32, loc, Location::GPR(tmp_in)); - a.emit_vcvtsi2sd_32(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out); - a.emit_mov(Size::S64, Location::XMM(tmp_out), ret); + if a.arch_has_fconverti() { + let tmp_out = self.machine.acquire_temp_xmm().unwrap(); + let tmp_in = self.machine.acquire_temp_gpr().unwrap(); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + loc, + Location::GPR(tmp_in), + ); + a.arch_emit_f64_convert_si32(tmp_in, tmp_out); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S64, + Location::XMM(tmp_out), + ret, + ); + self.machine.release_temp_gpr(tmp_in); + self.machine.release_temp_xmm(tmp_out); + } else { + let tmp_out = self.machine.acquire_temp_xmm().unwrap(); + let tmp_in = self.machine.acquire_temp_gpr().unwrap(); - self.machine.release_temp_gpr(tmp_in); - self.machine.release_temp_xmm(tmp_out); + a.emit_mov(Size::S32, loc, Location::GPR(tmp_in)); + a.emit_vcvtsi2sd_32(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out); + a.emit_mov(Size::S64, Location::XMM(tmp_out), ret); + + self.machine.release_temp_gpr(tmp_in); + self.machine.release_temp_xmm(tmp_out); + } } Operator::F64ConvertUI32 => { let loc = @@ -3724,15 +4030,40 @@ impl FunctionCodeGenerator for X64FunctionCode { false, )[0]; self.value_stack.push(ret); - let tmp_out = self.machine.acquire_temp_xmm().unwrap(); - let tmp_in = self.machine.acquire_temp_gpr().unwrap(); - a.emit_mov(Size::S32, loc, Location::GPR(tmp_in)); - a.emit_vcvtsi2sd_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out); - a.emit_mov(Size::S64, Location::XMM(tmp_out), ret); + if a.arch_has_fconverti() { + let tmp_out = self.machine.acquire_temp_xmm().unwrap(); + let tmp_in = self.machine.acquire_temp_gpr().unwrap(); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + loc, + Location::GPR(tmp_in), + ); + a.arch_emit_f64_convert_ui32(tmp_in, tmp_out); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S64, + Location::XMM(tmp_out), + ret, + ); + self.machine.release_temp_gpr(tmp_in); + self.machine.release_temp_xmm(tmp_out); + } else { + let tmp_out = self.machine.acquire_temp_xmm().unwrap(); + let tmp_in = self.machine.acquire_temp_gpr().unwrap(); + + a.emit_mov(Size::S32, loc, Location::GPR(tmp_in)); + a.emit_vcvtsi2sd_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out); + a.emit_mov(Size::S64, Location::XMM(tmp_out), ret); - self.machine.release_temp_gpr(tmp_in); - self.machine.release_temp_xmm(tmp_out); + self.machine.release_temp_gpr(tmp_in); + self.machine.release_temp_xmm(tmp_out); + } } Operator::F64ConvertSI64 => { let loc = @@ -3743,15 +4074,40 @@ impl FunctionCodeGenerator for X64FunctionCode { false, )[0]; self.value_stack.push(ret); - let tmp_out = self.machine.acquire_temp_xmm().unwrap(); - let tmp_in = self.machine.acquire_temp_gpr().unwrap(); - a.emit_mov(Size::S64, loc, Location::GPR(tmp_in)); - a.emit_vcvtsi2sd_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out); - a.emit_mov(Size::S64, Location::XMM(tmp_out), ret); + if a.arch_has_fconverti() { + let tmp_out = self.machine.acquire_temp_xmm().unwrap(); + let tmp_in = self.machine.acquire_temp_gpr().unwrap(); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S64, + loc, + Location::GPR(tmp_in), + ); + a.arch_emit_f64_convert_si64(tmp_in, tmp_out); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S64, + Location::XMM(tmp_out), + ret, + ); + self.machine.release_temp_gpr(tmp_in); + self.machine.release_temp_xmm(tmp_out); + } else { + let tmp_out = self.machine.acquire_temp_xmm().unwrap(); + let tmp_in = self.machine.acquire_temp_gpr().unwrap(); + + a.emit_mov(Size::S64, loc, Location::GPR(tmp_in)); + a.emit_vcvtsi2sd_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out); + a.emit_mov(Size::S64, Location::XMM(tmp_out), ret); - self.machine.release_temp_gpr(tmp_in); - self.machine.release_temp_xmm(tmp_out); + self.machine.release_temp_gpr(tmp_in); + self.machine.release_temp_xmm(tmp_out); + } } Operator::F64ConvertUI64 => { let loc = @@ -3762,31 +4118,56 @@ impl FunctionCodeGenerator for X64FunctionCode { false, )[0]; self.value_stack.push(ret); - let tmp_out = self.machine.acquire_temp_xmm().unwrap(); - let tmp_in = self.machine.acquire_temp_gpr().unwrap(); - let tmp = self.machine.acquire_temp_gpr().unwrap(); - let do_convert = a.get_label(); - let end_convert = a.get_label(); - - a.emit_mov(Size::S64, loc, Location::GPR(tmp_in)); - a.emit_test_gpr_64(tmp_in); - a.emit_jmp(Condition::Signed, do_convert); - a.emit_vcvtsi2sd_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out); - a.emit_jmp(Condition::None, end_convert); - a.emit_label(do_convert); - a.emit_mov(Size::S64, Location::GPR(tmp_in), Location::GPR(tmp)); - a.emit_and(Size::S64, Location::Imm32(1), Location::GPR(tmp)); - a.emit_shr(Size::S64, Location::Imm8(1), Location::GPR(tmp_in)); - a.emit_or(Size::S64, Location::GPR(tmp), Location::GPR(tmp_in)); - a.emit_vcvtsi2sd_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out); - a.emit_vaddsd(tmp_out, XMMOrMemory::XMM(tmp_out), tmp_out); - a.emit_label(end_convert); - a.emit_mov(Size::S64, Location::XMM(tmp_out), ret); - - self.machine.release_temp_gpr(tmp); - self.machine.release_temp_gpr(tmp_in); - self.machine.release_temp_xmm(tmp_out); + if a.arch_has_fconverti() { + let tmp_out = self.machine.acquire_temp_xmm().unwrap(); + let tmp_in = self.machine.acquire_temp_gpr().unwrap(); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S64, + loc, + Location::GPR(tmp_in), + ); + a.arch_emit_f64_convert_ui64(tmp_in, tmp_out); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S64, + Location::XMM(tmp_out), + ret, + ); + self.machine.release_temp_gpr(tmp_in); + self.machine.release_temp_xmm(tmp_out); + } else { + let tmp_out = self.machine.acquire_temp_xmm().unwrap(); + let tmp_in = self.machine.acquire_temp_gpr().unwrap(); + let tmp = self.machine.acquire_temp_gpr().unwrap(); + + let do_convert = a.get_label(); + let end_convert = a.get_label(); + + a.emit_mov(Size::S64, loc, Location::GPR(tmp_in)); + a.emit_test_gpr_64(tmp_in); + a.emit_jmp(Condition::Signed, do_convert); + a.emit_vcvtsi2sd_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out); + a.emit_jmp(Condition::None, end_convert); + a.emit_label(do_convert); + a.emit_mov(Size::S64, Location::GPR(tmp_in), Location::GPR(tmp)); + a.emit_and(Size::S64, Location::Imm32(1), Location::GPR(tmp)); + a.emit_shr(Size::S64, Location::Imm8(1), Location::GPR(tmp_in)); + a.emit_or(Size::S64, Location::GPR(tmp), Location::GPR(tmp_in)); + a.emit_vcvtsi2sd_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out); + a.emit_vaddsd(tmp_out, XMMOrMemory::XMM(tmp_out), tmp_out); + a.emit_label(end_convert); + a.emit_mov(Size::S64, Location::XMM(tmp_out), ret); + + self.machine.release_temp_gpr(tmp); + self.machine.release_temp_gpr(tmp_in); + self.machine.release_temp_xmm(tmp_out); + } } Operator::Call { function_index } => { diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index 1d0127cf7b5..f620e5f82cd 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -173,6 +173,26 @@ pub trait Emitter { fn emit_homomorphic_host_redirection(&mut self, target: GPR); fn emit_inline_breakpoint(&mut self, ty: InlineBreakpointType); + + fn arch_has_itruncf(&self) -> bool { false } + fn arch_emit_i32_trunc_sf32(&mut self, _src: XMM, _dst: GPR) { unimplemented!() } + fn arch_emit_i32_trunc_sf64(&mut self, _src: XMM, _dst: GPR) { unimplemented!() } + fn arch_emit_i32_trunc_uf32(&mut self, _src: XMM, _dst: GPR) { unimplemented!() } + fn arch_emit_i32_trunc_uf64(&mut self, _src: XMM, _dst: GPR) { unimplemented!() } + fn arch_emit_i64_trunc_sf32(&mut self, _src: XMM, _dst: GPR) { unimplemented!() } + fn arch_emit_i64_trunc_sf64(&mut self, _src: XMM, _dst: GPR) { unimplemented!() } + fn arch_emit_i64_trunc_uf32(&mut self, _src: XMM, _dst: GPR) { unimplemented!() } + fn arch_emit_i64_trunc_uf64(&mut self, _src: XMM, _dst: GPR) { unimplemented!() } + + fn arch_has_fconverti(&self) -> bool { false } + fn arch_emit_f32_convert_si32(&mut self, _src: GPR, _dst: XMM) { unimplemented!() } + fn arch_emit_f32_convert_si64(&mut self, _src: GPR, _dst: XMM) { unimplemented!() } + fn arch_emit_f32_convert_ui32(&mut self, _src: GPR, _dst: XMM) { unimplemented!() } + fn arch_emit_f32_convert_ui64(&mut self, _src: GPR, _dst: XMM) { unimplemented!() } + fn arch_emit_f64_convert_si32(&mut self, _src: GPR, _dst: XMM) { unimplemented!() } + fn arch_emit_f64_convert_si64(&mut self, _src: GPR, _dst: XMM) { unimplemented!() } + fn arch_emit_f64_convert_ui32(&mut self, _src: GPR, _dst: XMM) { unimplemented!() } + fn arch_emit_f64_convert_ui64(&mut self, _src: GPR, _dst: XMM) { unimplemented!() } } fn _dummy(a: &mut Assembler) { diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index d72d389ca0b..5df26714f6f 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -400,6 +400,57 @@ macro_rules! avx_fn { } } +macro_rules! avx_fn_bitwise_inv { + ($ins:ident, $width:ident, $width_int:ident, $name:ident) => { + fn $name(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + match src2 { + XMMOrMemory::XMM(src2) => dynasm!(self ; $ins $width(map_xmm(dst).v()), $width(map_xmm(src1).v()), $width(map_xmm(src2).v())), + XMMOrMemory::Memory(base, disp) => { + if disp >= 0 { + dynasm!(self ; b >after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { + fn $name(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + match src2 { + XMMOrMemory::XMM(src2) => dynasm!(self ; $ins $width(map_xmm(dst).v()), $width(map_xmm(src2).v()), $width(map_xmm(src1).v())), + XMMOrMemory::Memory(base, disp) => { + if disp >= 0 { + dynasm!(self ; b >after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { fn $name(&mut self, src1: XMM, _src2: XMMOrMemory, dst: XMM) { @@ -1312,20 +1363,6 @@ impl Emitter for Assembler { } } - // TODO: These instructions are only used in FP opcodes. Implement later. - fn emit_btc_gpr_imm8_32(&mut self, src: u8, dst: GPR) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_btc_gpr_imm8_64(&mut self, src: u8, dst: GPR) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_cmovae_gpr_32(&mut self, src: GPR, dst: GPR) { - dynasm!(self ; .dword 0 ; .dword 29) - } - fn emit_cmovae_gpr_64(&mut self, src: GPR, dst: GPR) { - dynasm!(self ; .dword 0 ; .dword 29) - } - avx_fn!(fadd, S, W, emit_vaddss); avx_fn!(fsub, S, W, emit_vsubss); avx_fn!(fmul, S, W, emit_vmulss); @@ -1333,8 +1370,11 @@ impl Emitter for Assembler { avx_fn!(fmax, S, W, emit_vmaxss); avx_fn!(fmin, S, W, emit_vminss); avx_fn!(fcmgt, S, W, emit_vcmpgtss); + avx_fn_reversed!(fcmgt, S, W, emit_vcmpltss); // b gt a <=> a lt b avx_fn!(fcmge, S, W, emit_vcmpgess); + avx_fn_bitwise_inv!(fcmgt, S, W, emit_vcmpless); // a not gt b <=> a le b avx_fn!(fcmeq, S, W, emit_vcmpeqss); + avx_fn_bitwise_inv!(fcmeq, S, W, emit_vcmpneqss); // a not eq b <=> a neq b avx_fn_unop!(fsqrt, S, emit_vsqrtss); avx_fn_unop!(frintn, S, emit_vroundss_nearest); // to nearest with ties to even avx_fn_unop!(frintm, S, emit_vroundss_floor); // toward minus infinity @@ -1349,8 +1389,11 @@ impl Emitter for Assembler { avx_fn!(fmax, D, X, emit_vmaxsd); avx_fn!(fmin, D, X, emit_vminsd); avx_fn!(fcmgt, D, X, emit_vcmpgtsd); + avx_fn_reversed!(fcmgt, D, X, emit_vcmpltsd); // b gt a <=> a lt b avx_fn!(fcmge, D, X, emit_vcmpgesd); + avx_fn_bitwise_inv!(fcmgt, D, X, emit_vcmplesd); // a not gt b <=> a le b avx_fn!(fcmeq, D, X, emit_vcmpeqsd); + avx_fn_bitwise_inv!(fcmeq, D, X, emit_vcmpneqsd); // a not eq b <=> a neq b avx_fn_unop!(fsqrt, D, emit_vsqrtsd); avx_fn_unop!(frintn, D, emit_vroundsd_nearest); // to nearest with ties to even avx_fn_unop!(frintm, D, emit_vroundsd_floor); // toward minus infinity @@ -1358,63 +1401,103 @@ impl Emitter for Assembler { avx_fn_unop!(frintz, D, emit_vroundsd_trunc); // toward zero avx_fn_cvt!(fcvt, D, S, emit_vcvtsd2ss); - fn emit_vcmpneqss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) + fn arch_has_itruncf(&self) -> bool { true } + fn arch_emit_i32_trunc_sf32(&mut self, src: XMM, dst: GPR) { + dynasm!(self ; fcvtzs W(map_gpr(dst).x()), S(map_xmm(src).v())); } - fn emit_vcmpneqsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) + fn arch_emit_i32_trunc_sf64(&mut self, src: XMM, dst: GPR) { + dynasm!(self ; fcvtzs W(map_gpr(dst).x()), D(map_xmm(src).v())); } - - fn emit_vcmpltss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) + fn arch_emit_i32_trunc_uf32(&mut self, src: XMM, dst: GPR) { + dynasm!(self ; fcvtzu W(map_gpr(dst).x()), S(map_xmm(src).v())); } - fn emit_vcmpltsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) + fn arch_emit_i32_trunc_uf64(&mut self, src: XMM, dst: GPR) { + dynasm!(self ; fcvtzu W(map_gpr(dst).x()), D(map_xmm(src).v())); } - - fn emit_vcmpless(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) + fn arch_emit_i64_trunc_sf32(&mut self, src: XMM, dst: GPR) { + dynasm!(self ; fcvtzs X(map_gpr(dst).x()), S(map_xmm(src).v())); + } + fn arch_emit_i64_trunc_sf64(&mut self, src: XMM, dst: GPR) { + dynasm!(self ; fcvtzs X(map_gpr(dst).x()), D(map_xmm(src).v())); } - fn emit_vcmplesd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) + fn arch_emit_i64_trunc_uf32(&mut self, src: XMM, dst: GPR) { + dynasm!(self ; fcvtzu X(map_gpr(dst).x()), S(map_xmm(src).v())); + } + fn arch_emit_i64_trunc_uf64(&mut self, src: XMM, dst: GPR) { + dynasm!(self ; fcvtzu X(map_gpr(dst).x()), D(map_xmm(src).v())); } + fn arch_has_fconverti(&self) -> bool { true } + fn arch_emit_f32_convert_si32(&mut self, src: GPR, dst: XMM) { + dynasm!(self ; scvtf S(map_xmm(dst).v()), W(map_gpr(src).x())); + } + fn arch_emit_f32_convert_si64(&mut self, src: GPR, dst: XMM) { + dynasm!(self ; scvtf S(map_xmm(dst).v()), X(map_gpr(src).x())); + } + fn arch_emit_f32_convert_ui32(&mut self, src: GPR, dst: XMM) { + dynasm!(self ; ucvtf S(map_xmm(dst).v()), W(map_gpr(src).x())); + } + fn arch_emit_f32_convert_ui64(&mut self, src: GPR, dst: XMM) { + dynasm!(self ; ucvtf S(map_xmm(dst).v()), X(map_gpr(src).x())); + } + fn arch_emit_f64_convert_si32(&mut self, src: GPR, dst: XMM) { + dynasm!(self ; scvtf D(map_xmm(dst).v()), W(map_gpr(src).x())); + } + fn arch_emit_f64_convert_si64(&mut self, src: GPR, dst: XMM) { + dynasm!(self ; scvtf D(map_xmm(dst).v()), X(map_gpr(src).x())); + } + fn arch_emit_f64_convert_ui32(&mut self, src: GPR, dst: XMM) { + dynasm!(self ; ucvtf D(map_xmm(dst).v()), W(map_gpr(src).x())); + } + fn arch_emit_f64_convert_ui64(&mut self, src: GPR, dst: XMM) { + dynasm!(self ; ucvtf D(map_xmm(dst).v()), X(map_gpr(src).x())); + } + // These instructions are only used in itruncf-type/fconverti-type opcodes. + fn emit_btc_gpr_imm8_32(&mut self, src: u8, dst: GPR) { + unimplemented!(); + } + fn emit_btc_gpr_imm8_64(&mut self, src: u8, dst: GPR) { + unimplemented!(); + } + fn emit_cmovae_gpr_32(&mut self, src: GPR, dst: GPR) { + unimplemented!(); + } + fn emit_cmovae_gpr_64(&mut self, src: GPR, dst: GPR) { + unimplemented!(); + } fn emit_ucomiss(&mut self, src: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) + unimplemented!(); } fn emit_ucomisd(&mut self, src: XMMOrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) + unimplemented!(); } - fn emit_cvttss2si_32(&mut self, src: XMMOrMemory, dst: GPR) { - dynasm!(self ; .dword 0 ; .dword 29) + unimplemented!(); } fn emit_cvttss2si_64(&mut self, src: XMMOrMemory, dst: GPR) { - dynasm!(self ; .dword 0 ; .dword 29) + unimplemented!(); } fn emit_cvttsd2si_32(&mut self, src: XMMOrMemory, dst: GPR) { - dynasm!(self ; .dword 0 ; .dword 29) + unimplemented!(); } fn emit_cvttsd2si_64(&mut self, src: XMMOrMemory, dst: GPR) { - dynasm!(self ; .dword 0 ; .dword 29) + unimplemented!(); } - fn emit_vcvtsi2ss_32(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) + unimplemented!(); } fn emit_vcvtsi2ss_64(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) + unimplemented!(); } fn emit_vcvtsi2sd_32(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) + unimplemented!(); } fn emit_vcvtsi2sd_64(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { - dynasm!(self ; .dword 0 ; .dword 29) + unimplemented!(); } - fn emit_test_gpr_64(&mut self, reg: GPR) { - dynasm!(self ; .dword 0 ; .dword 29) + unimplemented!(); } fn emit_ud2(&mut self) { From 001213716e1f086dc1d74c2e1c1819414e385452 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 7 Nov 2019 01:30:27 +0800 Subject: [PATCH 075/342] Add fneg. --- lib/singlepass-backend/src/codegen_x64.rs | 65 ++++++++++++++++--- lib/singlepass-backend/src/emitter_x64.rs | 4 ++ .../src/translator_aarch64.rs | 8 +++ 3 files changed, 67 insertions(+), 10 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 5afa0f92832..91f51e21677 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -2969,11 +2969,34 @@ impl FunctionCodeGenerator for X64FunctionCode { false, )[0]; self.value_stack.push(ret); - let tmp = self.machine.acquire_temp_gpr().unwrap(); - a.emit_mov(Size::S32, loc, Location::GPR(tmp)); - a.emit_btc_gpr_imm8_32(31, tmp); - a.emit_mov(Size::S32, Location::GPR(tmp), ret); - self.machine.release_temp_gpr(tmp); + + if a.arch_has_fneg() { + let tmp = self.machine.acquire_temp_xmm().unwrap(); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + loc, + Location::XMM(tmp), + ); + a.arch_emit_f32_neg(tmp, tmp); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S32, + Location::XMM(tmp), + ret, + ); + self.machine.release_temp_xmm(tmp); + } else { + let tmp = self.machine.acquire_temp_gpr().unwrap(); + a.emit_mov(Size::S32, loc, Location::GPR(tmp)); + a.emit_btc_gpr_imm8_32(31, tmp); + a.emit_mov(Size::S32, Location::GPR(tmp), ret); + self.machine.release_temp_gpr(tmp); + } } Operator::F64Const { value } => { @@ -3162,11 +3185,33 @@ impl FunctionCodeGenerator for X64FunctionCode { false, )[0]; self.value_stack.push(ret); - let tmp = self.machine.acquire_temp_gpr().unwrap(); - a.emit_mov(Size::S64, loc, Location::GPR(tmp)); - a.emit_btc_gpr_imm8_64(63, tmp); - a.emit_mov(Size::S64, Location::GPR(tmp), ret); - self.machine.release_temp_gpr(tmp); + if a.arch_has_fneg() { + let tmp = self.machine.acquire_temp_xmm().unwrap(); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S64, + loc, + Location::XMM(tmp), + ); + a.arch_emit_f64_neg(tmp, tmp); + Self::emit_relaxed_binop( + a, + &mut self.machine, + Assembler::emit_mov, + Size::S64, + Location::XMM(tmp), + ret, + ); + self.machine.release_temp_xmm(tmp); + } else { + let tmp = self.machine.acquire_temp_gpr().unwrap(); + a.emit_mov(Size::S64, loc, Location::GPR(tmp)); + a.emit_btc_gpr_imm8_64(63, tmp); + a.emit_mov(Size::S64, Location::GPR(tmp), ret); + self.machine.release_temp_gpr(tmp); + } } Operator::F64PromoteF32 => Self::emit_fp_unop_avx( diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index f620e5f82cd..e34cf6e8eb3 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -193,6 +193,10 @@ pub trait Emitter { fn arch_emit_f64_convert_si64(&mut self, _src: GPR, _dst: XMM) { unimplemented!() } fn arch_emit_f64_convert_ui32(&mut self, _src: GPR, _dst: XMM) { unimplemented!() } fn arch_emit_f64_convert_ui64(&mut self, _src: GPR, _dst: XMM) { unimplemented!() } + + fn arch_has_fneg(&self) -> bool { false } + fn arch_emit_f32_neg(&mut self, _src: XMM, _dst: XMM) { unimplemented!() } + fn arch_emit_f64_neg(&mut self, _src: XMM, _dst: XMM) { unimplemented!() } } fn _dummy(a: &mut Assembler) { diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 5df26714f6f..5083ca84457 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -1453,6 +1453,14 @@ impl Emitter for Assembler { dynasm!(self ; ucvtf D(map_xmm(dst).v()), X(map_gpr(src).x())); } + fn arch_has_fneg(&self) -> bool { true } + fn arch_emit_f32_neg(&mut self, src: XMM, dst: XMM) { + dynasm!(self ; fneg S(map_xmm(dst).v()), S(map_xmm(src).v())); + } + fn arch_emit_f64_neg(&mut self, src: XMM, dst: XMM) { + dynasm!(self ; fneg D(map_xmm(dst).v()), D(map_xmm(src).v())); + } + // These instructions are only used in itruncf-type/fconverti-type opcodes. fn emit_btc_gpr_imm8_32(&mut self, src: u8, dst: GPR) { unimplemented!(); From 50c30ab212682628f58a61f31eb7b1c317eed897 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 7 Nov 2019 01:30:45 +0800 Subject: [PATCH 076/342] runtime-core: Support cross-compilation. --- lib/runtime-core/build.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/runtime-core/build.rs b/lib/runtime-core/build.rs index 81884f0e18b..3a549e45fd4 100644 --- a/lib/runtime-core/build.rs +++ b/lib/runtime-core/build.rs @@ -29,14 +29,20 @@ fn main() { println!("cargo:rustc-cfg=nightly"); } - if cfg!(all(target_os = "linux", target_arch = "x86_64")) { - cc::Build::new() - .file("image-loading-linux-x86-64.s") - .compile("image-loading"); - } else if cfg!(all(target_os = "macos", target_arch = "x86_64")) { - cc::Build::new() - .file("image-loading-macos-x86-64.s") - .compile("image-loading"); - } else { + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + + match (target_os.as_str(), target_arch.as_str()) { + ("linux", "x86_64") => { + cc::Build::new() + .file("image-loading-linux-x86-64.s") + .compile("image-loading"); + } + ("macos", "x86_64") => { + cc::Build::new() + .file("image-loading-macos-x86-64.s") + .compile("image-loading"); + } + _ => {} } } From 203efd0c060a85e24b912e54566651bbd8f8464f Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Wed, 6 Nov 2019 23:25:39 -0800 Subject: [PATCH 077/342] Apply TBAA to the correct instruction. Caught by LLVM verifier complaining about !tbaa on a getelementptr. --- lib/llvm-backend/src/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index 4c34b6d584a..143c9bba420 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -1037,7 +1037,7 @@ impl<'a> CtxType<'a> { module.clone(), intrinsics, field_name, - globals_array_ptr_ptr.as_instruction_value().unwrap(), + global_array_ptr.as_instruction_value().unwrap(), None, ); let const_index = intrinsics.i32_ty.const_int(index, false); From dfaad35f8dabc3a8143c48604a00aa9c44dc04b6 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 7 Nov 2019 14:31:43 +0100 Subject: [PATCH 078/342] fix(spectests) Remove a warning. --- lib/spectests/examples/test.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/spectests/examples/test.rs b/lib/spectests/examples/test.rs index 8ce199695fc..006fc1397d2 100644 --- a/lib/spectests/examples/test.rs +++ b/lib/spectests/examples/test.rs @@ -1,5 +1,4 @@ use wabt::wat2wasm; -use wasmer_clif_backend::CraneliftCompiler; use wasmer_runtime_core::{backend::Compiler, import::ImportObject, Instance}; fn main() { From 2e05104d45b91f0efe448b82cb6814972b465e92 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 7 Nov 2019 14:32:19 +0100 Subject: [PATCH 079/342] fix(runtime-core) Introduce `Context::ExternalWithEnv`. Host functions use `Context::External` with a `*mut vm::FuncCtx` pointer, casted to `*mut vm::Ctx`. It creates a conflict with exports that also use `Context::External`. This patch introduces `Context::ExternalWithEnv` to create a specific path in the code for an external context with `*mut vm::FuncEnv`. This patch fixes all the `linking.wast` tests in the spectests. --- lib/runtime-core/src/backing.rs | 23 ++++++++++++++--------- lib/runtime-core/src/export.rs | 3 ++- lib/runtime-core/src/instance.rs | 2 +- lib/runtime-core/src/typed_func.rs | 6 +----- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/lib/runtime-core/src/backing.rs b/lib/runtime-core/src/backing.rs index 2493e9d35bc..7449403fa62 100644 --- a/lib/runtime-core/src/backing.rs +++ b/lib/runtime-core/src/backing.rs @@ -591,16 +591,21 @@ fn import_functions( // ^^^^^^^^ `vm::FuncCtx` is purposely leaked. // It is dropped by the specific `Drop` // implementation of `ImportBacking`. - vmctx: NonNull::new(vmctx).expect("`vmctx` must not be null."), - func_env: match ctx { - Context::External(ctx) => { - NonNull::new(ctx).map(NonNull::cast) - // ^^^^^^^^^^^^^ - // `*mut vm::FuncEnv` was casted to - // `*mut vm::Ctx` to fit in - // `Context::External`. Cast it back. + vmctx: NonNull::new(match ctx { + Context::External(vmctx) => vmctx, + Context::ExternalWithEnv(vmctx_, _) => { + if vmctx_.is_null() { + vmctx + } else { + vmctx_ + } } - Context::Internal => None, + _ => vmctx, + }) + .expect("`vmctx` must not be null."), + func_env: match ctx { + Context::ExternalWithEnv(_, func_env) => Some(func_env), + _ => None, }, }))) .unwrap(), diff --git a/lib/runtime-core/src/export.rs b/lib/runtime-core/src/export.rs index 7960d76e699..88ec07e402c 100644 --- a/lib/runtime-core/src/export.rs +++ b/lib/runtime-core/src/export.rs @@ -3,11 +3,12 @@ use crate::{ module::ModuleInner, table::Table, types::FuncSig, vm, }; use indexmap::map::Iter as IndexMapIter; -use std::sync::Arc; +use std::{ptr::NonNull, sync::Arc}; #[derive(Debug, Copy, Clone)] pub enum Context { External(*mut vm::Ctx), + ExternalWithEnv(*mut vm::Ctx, NonNull), Internal, } diff --git a/lib/runtime-core/src/instance.rs b/lib/runtime-core/src/instance.rs index 5cf92a312f9..53a5681ff5d 100644 --- a/lib/runtime-core/src/instance.rs +++ b/lib/runtime-core/src/instance.rs @@ -413,6 +413,7 @@ impl InstanceInner { ctx: match ctx { Context::Internal => Context::External(self.vmctx), ctx @ Context::External(_) => ctx, + func_ctx @ Context::ExternalWithEnv(_, _) => func_ctx, }, signature, } @@ -463,7 +464,6 @@ impl InstanceInner { }; let signature = SigRegistry.lookup_signature_ref(&module.info.signatures[sig_index]); - // let signature = &module.info.signatures[sig_index]; (unsafe { FuncPointer::new(func_ptr) }, ctx, signature) } diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 8c6a7826d86..cce0581826a 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -724,11 +724,7 @@ where fn to_export(&self) -> Export { let func = unsafe { FuncPointer::new(self.func.as_ptr()) }; let ctx = match self.func_env { - Some(func_env) => Context::External(func_env.cast().as_ptr()), - // ^^^^^^ - // `Context::External` expects a `vm::Ctx`. - // Casting to `vm::FuncCtx` happens in the - // `backing` module. + Some(func_env) => Context::ExternalWithEnv(self.vmctx, func_env), None => Context::Internal, }; let signature = Arc::new(FuncSig::new(Args::types(), Rets::types())); From ba87af5b1a78a9b7e2f58fb8fdca75df0d4b172d Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 7 Nov 2019 20:44:17 +0100 Subject: [PATCH 080/342] feat(runtime-core) Ability for an export function to get a func env. --- lib/runtime-core/src/backing.rs | 4 ++-- lib/runtime-core/src/export.rs | 2 +- lib/runtime-core/src/instance.rs | 36 ++++++++++++++++++------------ lib/runtime-core/src/typed_func.rs | 5 +++-- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/lib/runtime-core/src/backing.rs b/lib/runtime-core/src/backing.rs index 7449403fa62..dc000957e93 100644 --- a/lib/runtime-core/src/backing.rs +++ b/lib/runtime-core/src/backing.rs @@ -600,11 +600,11 @@ fn import_functions( vmctx_ } } - _ => vmctx, + Context::Internal => vmctx, }) .expect("`vmctx` must not be null."), func_env: match ctx { - Context::ExternalWithEnv(_, func_env) => Some(func_env), + Context::ExternalWithEnv(_, func_env) => func_env, _ => None, }, }))) diff --git a/lib/runtime-core/src/export.rs b/lib/runtime-core/src/export.rs index 88ec07e402c..54427cf6bd0 100644 --- a/lib/runtime-core/src/export.rs +++ b/lib/runtime-core/src/export.rs @@ -8,7 +8,7 @@ use std::{ptr::NonNull, sync::Arc}; #[derive(Debug, Copy, Clone)] pub enum Context { External(*mut vm::Ctx), - ExternalWithEnv(*mut vm::Ctx, NonNull), + ExternalWithEnv(*mut vm::Ctx, Option>), Internal, } diff --git a/lib/runtime-core/src/instance.rs b/lib/runtime-core/src/instance.rs index 53a5681ff5d..ae5eef69579 100644 --- a/lib/runtime-core/src/instance.rs +++ b/lib/runtime-core/src/instance.rs @@ -133,7 +133,7 @@ impl Instance { .expect("wasm trampoline"); let start_func: Func<(), (), Wasm> = - unsafe { Func::from_raw_parts(wasm_trampoline, func_ptr, ctx_ptr) }; + unsafe { Func::from_raw_parts(wasm_trampoline, func_ptr, None, ctx_ptr) }; start_func.call()?; } @@ -214,20 +214,26 @@ impl Instance { .get_trampoline(&self.module.info, sig_index) .unwrap(); - let func_ptr = match func_index.local_or_import(&self.module.info) { - LocalOrImport::Local(local_func_index) => self - .module - .runnable_module - .get_func(&self.module.info, local_func_index) - .unwrap(), - LocalOrImport::Import(import_func_index) => NonNull::new( - self.inner.import_backing.vm_functions[import_func_index].func as *mut _, - ) - .unwrap(), + let (func_ptr, func_env) = match func_index.local_or_import(&self.module.info) { + LocalOrImport::Local(local_func_index) => ( + self.module + .runnable_module + .get_func(&self.module.info, local_func_index) + .unwrap(), + None, + ), + LocalOrImport::Import(import_func_index) => { + let imported_func = &self.inner.import_backing.vm_functions[import_func_index]; + + ( + NonNull::new(imported_func.func as *mut _).unwrap(), + unsafe { imported_func.func_ctx.as_ref() }.func_env, + ) + } }; let typed_func: Func = - unsafe { Func::from_raw_parts(func_wasm_inner, func_ptr, ctx) }; + unsafe { Func::from_raw_parts(func_wasm_inner, func_ptr, func_env, ctx) }; Ok(typed_func) } else { @@ -413,7 +419,7 @@ impl InstanceInner { ctx: match ctx { Context::Internal => Context::External(self.vmctx), ctx @ Context::External(_) => ctx, - func_ctx @ Context::ExternalWithEnv(_, _) => func_ctx, + ctx @ Context::ExternalWithEnv(_, _) => ctx, }, signature, } @@ -456,9 +462,11 @@ impl InstanceInner { ), LocalOrImport::Import(imported_func_index) => { let imported_func = &self.import_backing.vm_functions[imported_func_index]; + let func_ctx = unsafe { imported_func.func_ctx.as_ref() }; + ( imported_func.func as *const _, - Context::External(unsafe { imported_func.func_ctx.as_ref() }.vmctx.as_ptr()), + Context::ExternalWithEnv(func_ctx.vmctx.as_ptr(), func_ctx.func_env), ) } }; diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index cce0581826a..7bb7e63cccb 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -227,12 +227,13 @@ where pub(crate) unsafe fn from_raw_parts( inner: Wasm, func: NonNull, + func_env: Option>, vmctx: *mut vm::Ctx, ) -> Func<'a, Args, Rets, Wasm> { Func { inner, func, - func_env: None, + func_env, vmctx, _phantom: PhantomData, } @@ -724,7 +725,7 @@ where fn to_export(&self) -> Export { let func = unsafe { FuncPointer::new(self.func.as_ptr()) }; let ctx = match self.func_env { - Some(func_env) => Context::ExternalWithEnv(self.vmctx, func_env), + func_env @ Some(_) => Context::ExternalWithEnv(self.vmctx, func_env), None => Context::Internal, }; let signature = Arc::new(FuncSig::new(Args::types(), Rets::types())); From dccaa3a2855360658c8208f2e60ef89ab32b6902 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 7 Nov 2019 12:42:29 -0800 Subject: [PATCH 081/342] Apply TBAA to the correct instruction. Another instance of the bug in PR #933. --- lib/llvm-backend/src/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index 143c9bba420..fe1c72d932d 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -1055,7 +1055,7 @@ impl<'a> CtxType<'a> { module.clone(), intrinsics, "global_ptr", - globals_array_ptr_ptr.as_instruction_value().unwrap(), + global_ptr.as_instruction_value().unwrap(), Some(index as u32), ); From 37268b2f46b16bff3a7ab85d076cb0b8e3dd88e0 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 8 Nov 2019 10:41:42 -0800 Subject: [PATCH 082/342] Pass --enable-all to wasm2json when building corpus out of spectests. --- fuzz/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzz/README.md b/fuzz/README.md index 00939ee5a74..36f7e0c4ca4 100644 --- a/fuzz/README.md +++ b/fuzz/README.md @@ -47,7 +47,7 @@ The fuzzer works best when it has examples of small Wasm files to start with. Us ```sh mkdir spec-test-corpus -for i in lib/spectests/spectests/*.wast; do wast2json $i -o spec-test-corpus/$(basename $i).json; done +for i in lib/spectests/spectests/*.wast; do wast2json --enable-all $i -o spec-test-corpus/$(basename $i).json; done mv spec-test-corpus/*.wasm fuzz/corpus/simple_instantiate/ rm -r spec-test-corpus ``` From 6370e1103417e1edafe540604c9fe002839d866b Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 8 Nov 2019 11:10:44 -0800 Subject: [PATCH 083/342] Fuzz all the backends. --- fuzz/Cargo.toml | 2 ++ fuzz/fuzz_targets/compile_wasm.rs | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 71344335595..8d6a38140ea 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -12,6 +12,8 @@ cargo-fuzz = true wasmer-runtime = { path = "../lib/runtime" } wasmer-runtime-core = { path = "../lib/runtime-core" } wasmer = { path = "../" } +wasmer-llvm-backend = { path = "../lib/llvm-backend" } +wasmer-singlepass-backend = { path = "../lib/singlepass-backend" } libfuzzer-sys = { git = "https://github.com/rust-fuzz/libfuzzer-sys.git" } # Prevent this from interfering with workspaces diff --git a/fuzz/fuzz_targets/compile_wasm.rs b/fuzz/fuzz_targets/compile_wasm.rs index 4abe062f510..e36d8c39630 100644 --- a/fuzz/fuzz_targets/compile_wasm.rs +++ b/fuzz/fuzz_targets/compile_wasm.rs @@ -2,9 +2,24 @@ #[macro_use] extern crate libfuzzer_sys; extern crate wasmer_runtime; +extern crate wasmer_runtime_core; +extern crate wasmer_llvm_backend; +extern crate wasmer_singlepass_backend; -use wasmer_runtime::compile; +use wasmer_runtime::{compile, compile_with}; +use wasmer_runtime_core::backend::Compiler; + +fn get_llvm_compiler() -> impl Compiler { + use wasmer_llvm_backend::LLVMCompiler; + LLVMCompiler::new() +} +fn get_singlepass_compiler() -> impl Compiler { + use wasmer_singlepass_backend::SinglePassCompiler; + SinglePassCompiler::new() +} fuzz_target!(|data: &[u8]| { + let _ = compile_with(data, &get_llvm_compiler()); let _ = compile(data); + let _ = compile_with(data, &get_singlepass_compiler()); }); From 64783423ea398176faa947481d04477f765bcbee Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Fri, 8 Nov 2019 11:13:01 -0800 Subject: [PATCH 084/342] Fix WASI append bug, add test --- CHANGELOG.md | 1 + lib/wasi-tests/build/wasitests.rs | 2 +- lib/wasi-tests/tests/wasitests/fd_append.rs | 18 +++++++ lib/wasi-tests/tests/wasitests/mod.rs | 1 + .../wasitests/close_preopen_fd.wasm | Bin 72342 -> 71549 bytes lib/wasi-tests/wasitests/create_dir.wasm | Bin 97754 -> 97044 bytes lib/wasi-tests/wasitests/envvar.wasm | Bin 79153 -> 78953 bytes lib/wasi-tests/wasitests/fd_allocate.wasm | Bin 82262 -> 81754 bytes lib/wasi-tests/wasitests/fd_append.out | 1 + lib/wasi-tests/wasitests/fd_append.rs | 48 ++++++++++++++++++ lib/wasi-tests/wasitests/fd_append.wasm | Bin 0 -> 81276 bytes lib/wasi-tests/wasitests/fd_close.wasm | Bin 83077 -> 82738 bytes lib/wasi-tests/wasitests/fd_pread.wasm | Bin 81768 -> 81542 bytes lib/wasi-tests/wasitests/fd_read.wasm | Bin 81138 -> 80914 bytes lib/wasi-tests/wasitests/fd_sync.wasm | Bin 82407 -> 81885 bytes lib/wasi-tests/wasitests/file_metadata.wasm | Bin 79603 -> 78946 bytes lib/wasi-tests/wasitests/fs_sandbox_test.wasm | Bin 73048 -> 72279 bytes lib/wasi-tests/wasitests/fseek.wasm | Bin 83533 -> 82625 bytes lib/wasi-tests/wasitests/hello.wasm | Bin 71817 -> 71008 bytes lib/wasi-tests/wasitests/mapdir.wasm | Bin 85016 -> 84381 bytes lib/wasi-tests/wasitests/path_link.wasm | Bin 82301 -> 81696 bytes lib/wasi-tests/wasitests/path_rename.wasm | Bin 86633 -> 85780 bytes lib/wasi-tests/wasitests/path_symlink.wasm | Bin 81240 -> 80571 bytes lib/wasi-tests/wasitests/poll_oneoff.wasm | Bin 90554 -> 90399 bytes lib/wasi-tests/wasitests/quine.wasm | Bin 80535 -> 80098 bytes lib/wasi-tests/wasitests/readlink.wasm | Bin 81683 -> 81100 bytes .../wasitests/wasi_sees_virtual_root.wasm | Bin 85555 -> 84410 bytes lib/wasi-tests/wasitests/writing.wasm | Bin 82201 -> 81812 bytes lib/wasi/src/syscalls/mod.rs | 20 ++++++-- 29 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 lib/wasi-tests/tests/wasitests/fd_append.rs create mode 100644 lib/wasi-tests/wasitests/fd_append.out create mode 100644 lib/wasi-tests/wasitests/fd_append.rs create mode 100755 lib/wasi-tests/wasitests/fd_append.wasm diff --git a/CHANGELOG.md b/CHANGELOG.md index afe906514e8..98a6679b5c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## **[Unreleased]** +- [#936](https://github.com/wasmerio/wasmer/pull/939) Fix bug causing attempts to append to files with WASI to delete the contents of the file - [#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 diff --git a/lib/wasi-tests/build/wasitests.rs b/lib/wasi-tests/build/wasitests.rs index 0144da92056..5ccda63c9fe 100644 --- a/lib/wasi-tests/build/wasitests.rs +++ b/lib/wasi-tests/build/wasitests.rs @@ -83,7 +83,7 @@ pub fn compile(file: &str, ignores: &HashSet) -> Option { .arg("+nightly") .arg("--target=wasm32-wasi") .arg("-C") - .arg("opt-level=s") + .arg("opt-level=z") .arg(file) .arg("-o") .arg(&wasm_out_name) diff --git a/lib/wasi-tests/tests/wasitests/fd_append.rs b/lib/wasi-tests/tests/wasitests/fd_append.rs new file mode 100644 index 00000000000..0ac3ea6ebf8 --- /dev/null +++ b/lib/wasi-tests/tests/wasitests/fd_append.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_append() { + assert_wasi_output!( + "../../wasitests/fd_append.wasm", + "fd_append", + vec![], + vec![( + ".".to_string(), + ::std::path::PathBuf::from("wasitests/test_fs/temp") + ),], + vec![], + "../../wasitests/fd_append.out" + ); +} diff --git a/lib/wasi-tests/tests/wasitests/mod.rs b/lib/wasi-tests/tests/wasitests/mod.rs index 75a91d6f003..d226dc0ee0d 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_append; mod fd_close; mod fd_pread; mod fd_read; diff --git a/lib/wasi-tests/wasitests/close_preopen_fd.wasm b/lib/wasi-tests/wasitests/close_preopen_fd.wasm index 56d37f64630ee0bbdf833ca87c31ffa239179398..5badfb755e571991c6327b4c6938de49b27a8cb7 100755 GIT binary patch delta 16319 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 K^~wWC7ylpN`}1G` delta 17042 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
8p3g9qO|C-+0 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 bIHNdH4*JJ5`r1GXR(or#zp;ln*~|X};Jghc delta 25349 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⪙rZPm(|PVB^+c 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 o5R@ns+B~6b%7 diff --git a/lib/wasi-tests/wasitests/fd_append.out b/lib/wasi-tests/wasitests/fd_append.out new file mode 100644 index 00000000000..e9d92ef26a6 --- /dev/null +++ b/lib/wasi-tests/wasitests/fd_append.out @@ -0,0 +1 @@ +"Hello, world!\nGoodbye, world!\n" diff --git a/lib/wasi-tests/wasitests/fd_append.rs b/lib/wasi-tests/wasitests/fd_append.rs new file mode 100644 index 00000000000..f1e55c5ed9a --- /dev/null +++ b/lib/wasi-tests/wasitests/fd_append.rs @@ -0,0 +1,48 @@ +// Args: +// mapdir: .:wasitests/test_fs/temp + +use std::fs::OpenOptions; +use std::io::{Read, Write}; +use std::path::PathBuf; + +static STR1: &str = "Hello, world!\n"; +static STR2: &str = "Goodbye, world!\n"; + +fn main() { + let file = { + #[cfg(not(target_os = "wasi"))] + let mut base = PathBuf::from("wasitests/test_fs/temp"); + #[cfg(target_os = "wasi")] + let mut base = PathBuf::from("."); + + base.push("fd_append_test"); + base + }; + + { + let mut file_handle = OpenOptions::new() + .create_new(true) + .append(true) + .open(&file) + .expect("Couldn't create file"); + file_handle.write(STR1.as_bytes()).unwrap(); + } + { + let mut file_handle = OpenOptions::new() + .append(true) + .open(&file) + .expect("Couldn't reopen file to append"); + file_handle.write(STR2.as_bytes()).unwrap(); + } + + let mut file_handle = OpenOptions::new() + .read(true) + .open(&file) + .expect("Couldn't reopen file to read"); + + let mut test = String::new(); + file_handle.read_to_string(&mut test); + + assert_eq!(&test, &format!("{}{}", STR1, STR2)); + println!("{:?}", &test); +} diff --git a/lib/wasi-tests/wasitests/fd_append.wasm b/lib/wasi-tests/wasitests/fd_append.wasm new file mode 100755 index 0000000000000000000000000000000000000000..b1c73d14fabb4fb89b4b6f6b98cccaba60375200 GIT binary patch literal 81276 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

uo>BghejkWV4hkR)U9wQ)DHp#6$C@Sy*|nww|$X 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 literal 0 HcmV?d00001 diff --git a/lib/wasi-tests/wasitests/fd_close.wasm b/lib/wasi-tests/wasitests/fd_close.wasm index 5ace5206203c7385f622705c2503474978339113..162e968755a7a3804afed610cf73c6c86dccb5d6 100755 GIT binary patch delta 22423 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 N$YQH_Y-17g{U2Y%)4u=! delta 22730 zcmb_^34ByV^8f3eGntv>1(J{p@@B%3aE2=ZV9uB0d)QSKmUQu>!Z55x~jUm zy1L&yJI^)uK35a%`k6N|P1D!|EcH4~yN-poG}*uy6ECsc@HYM&M-^ip4|6e%I~j9x zcY*^Sub0PtoZQJdbGc9tXy&Ca_3?PPO9Fb)g1I#A@@OuX%i{thDqIc^zJb*3ax(7p zIDyIIayng3x6>K+ai81gW=^-)>j8uY5HHXHv&#iKs4pjwxm*dH`9UN;37!Bw7z1vQ zlmx1iHIJsD%*#Q8hX_Zli+f!z4Wxi%7tnc~K+PS%%RMd-9l)2)br;6$bZY3_%RNk- z1MN4$IAvUVx7BIu}oWGLn79>e*rTDXZlX z{ylq`Kh7)pSL{djC0ou{^ELc_zJou;*Yb7zW&R3Je0`boInFiT`wr#|=SA?*Onq`l zYblfZTjE-0Pxgvf=4|i#OF1fo4uk7;VxO~b=oQKr@tsHOBATJ)bH6T2LTq3_Gm+nU zR1~^$TB>@c&mr6c1Kel6sp)T0Tg_(zkT8g8u7V`lI>-o>roSTAyFy_L%%{(%#MID)=j+Fq!lf{YACuZ+n^h!z<@g6AeQKoN`mTZIGbmQBla19b%=>_t zq6_?n6jG&Op%ex~(=mc7u-)9JHOzgCp@8=;b{J+vj~ZDlGb(kd2au({#?z zpA+H4K2ZCY6Z29mIsxHTYA;SCj{f~AamK;jVSaZW$O3bW$swkC=Oy&d&^l;-lS^Ih zpalY&;*U4Pp^>cAQS9*g88OCRhItFJdT9Z03{%HBBj_}>pv&MvH(?4pN@NA*F4zif zC^OuKYqB1te$f)PCm?$yTPbG`x+sI!T6m%B!8i#d4^3llLy1R6BKo5!T3N0 z#xMlSj3ekS)q-BXgT^ZdYBR@0L-K||PROzhCq7<*pn`vO7e!4rE|cZks0#RmtX%@aujom%-nY} zi})n$NG5el>r?p$8wV`de$t9C`Y+xzXk8DpSP#rg?+*Ex-UU zH=m@LhJib1(LksALMj038t7kSmlQa(VuudUd<>5UQzcF|4fE6GHMgW*%F<60VX&K# z$WCog0D8@#2G5H6v`$TrN6}jmFGMp|#M|R>OoY;VvrXdK^da7D)B)rs4y8A11_d!$ z5T;ZYs+cB7kcn%*%M?GR_vl=usLAK~At%%Yy_k*05`MVHJD{8YKPKC^p@-K?R(`pg!=Z)l*hvM|{y45-5OjUfH1aCumk`Yll66Ob;Jg$Y(+qAI*c7TVn>sKQf{`a}y7(}tRV z)o4f_Rd}coq+1n!urf>owYztz(zhh2&q4}85z^OWq0JJQ2P%9)7TScuZc*XWjhagZ zW9AdG(4}w!PJe{>9b}`WTV$;T%-3I<3^-+wKGUBf7-^1~{(5Z7?9Kc{7CF`Gbc8bcJgS8+h>1RWbDX3cHhh-jWty*_i>BkuO}5 zojLCN6#zEfHm&H{3;#%0s2YfXA9~@cr~<@M5ZMm%pYzRS_an8#H}g0EG%{uW{U4Ko3bq;AuGpoOj_ATMfeMa_@l$E z-7NM62f&p`ZV_`cXa%#}j3J@&QOillA;-Xg2X+N(vX-wcUR(#GrKy#})C#owsi0UE zz(+vAJq-oO{q&%!mROgI?7U#Ig*D)oWuJ>-c|m?EB5uyRfNc;P^9JO7u56jAw(Ob< ztBkz@J59Z2myyU|7k_^QxngXK5&Wl!sA!zot7l@Km9P_BP2#^&~-kv@_;2yEXsH7|*pk$WM*SBP|@ zJy_7+C@DQfT4w5olPEnk4;kD4G;=V4{yT>Zk<#+Yz;;3dorVK(vRvHWa(w>2_!4v; z#F8Fc_zmW(_Bxzlb~hKUR>6*ShlvW>_m~{mV?Kuet}Hg{{ZPsWZU#7)OAY591PQ$th*yKe`)4u`pyunmIg zaCFc#vk)ot9poT^m!P_KsjLQd1f36%@X;@~eC8euqD&U#1m&cj9bjb4=jU=i>ac(u z)D^HAjv{{g5b(hxr6M^@)ELa*y|g@wYE3^w3aMN=)D-cSuxJ@&hNk~Q6{5U#vycnj zN}tcw;NXk`>42o|CLqO&t+NKY%v06qF9qYUu$$A_ipU6N&Xw zDgGsbZ3@C$8_S8SJlImiYpIHQ-cAYqAc-Xevb$LW0%ASn2x#Q5d(RcbzQf~4&aI;b1zfrrSOqV`36 zG&L>aBhjKx!)}v2BXcuh($}e`)B@G{e6&KQaKMox9O#M2bAu%*0FP+cOXP=9;!(98 zWD%TEbIXKtMPswOI)JVgG;~FaIPo^*j_r)yYA43bZe{vMgr2kryc|qAG;=!j0UpJ5 zjIs+`oz-4Ra?w0cmzDfEk+HF&kl}dpox5Y8j*W@Cy0dX5x^LCijAHZIfe)M}pGC zzY8vG`GRB;IE>A!;yR$t?(C|zozcw$Z9C};mJ=CZg#JVWj@mzhBc=Tic0gR!J|ATF zxFxT{c?brFxD|hs0wFn}gj|mO?c3YC>4q2>4WREUf1q;$(R{xjm`hLu`F1m5T%Ia= z7bLSfF}%R=ETxs$tP_RPyEe7J%)rNXd}Rp}FHhp-Ad7 zmMs_4yQHy|;+Z!>iPnOqe^D-~Qqugi*(Av!h!PQJe!e2mXxS3abiFaKDt;l8C5;!m zmfcKvIEN;Yhx25&^LaR*cFPsT-8#aH_g1R6vdx+#~6`JkU^}oSC@|1#o75q3tK&O&5hz zmy7wud4}r84VhAzB^1OWl6q+rlGq^j78eH^IUk})k7D+BF|*x3-F4&n|w+OS0pB=R8K$Z6r zZYu<5+TM|@YU~}IuSz`It98NF!-Ov8%bdGL+AE}B7hKlfnh7wSF<-}W31WT_`3zV{ zcODjVF6frL`#wV7%-l{-7}qy0C~EOvrc+k$4x>IH!P>h1DP`dMoMk&zsR6+j@eA?b zSc`gT!_5uE6SJM6ktbyyQ5+K0z5Aus6A?vxfT1Ct$5R1OIZu4mJH#vQ7s-8!Jqzwf zyQew_-`1z7O@$y_MdnFz-t`w%m%e0*@nC_}mn%_D!(KD}DkvaH4zm*$h`ulh zXd78hR!*8WClQTyM{oRd6MK=gcdNz6gCFl0*6sdaZ`PR!vC%4(sxAGKPdyT zD{q4Q6WLXUK3^>F+m#&_@AhpL-hCL@0yyBHxSh<%$)XiF_R%65a+QWhk?;&xDVtra z3X#?>Mw|M0du47SW|+n13ds~}=xWiGc;!4+69Y>MsHWxE18)?Qdbya@Z~BnWB!*5P z8B?>mk*1zkloF#oiwKRCenE6B>DNqlWjQUxWrxYYp_QVdqyUEK>5_4BvmryBwDDyy z7b{6#Ar??>u03s0XJfYKqFG6rq5n%AJbJSRZCS#T{PcUPVN>}P1D5c(o|73G`+iY*NFC*(IfXf zhz+2$YvlfcAJTw?C^et(h?M?_`pGb!0qx2MFk*)k71R$CbL3h}VQcB0g*^Iuq+}tA z3-c2CXLzy0Am0uFsU21ksVxLg)u*kiZ=MDbu|h6iC&jK}bR3ulOOyU`DO z#2^lksoJI<+f78DTn4QZYW*;2@5KCh~ zM3T0WG?Y4c$#N`5h3ManofNzK7l*6Ke(Uu#I?bnlte!-wEp(7!xu25ahH?*Sux5aY z%Jmpj!ulWs17uJhzB3Tm{sNJKsHfb~!ia#Qiac`I#ohsK?pr6On`y#7&^InM^y`KKMc$Ey0+4sm z%30*C8f24)ZfN)FBk~*|@54beI$J!Ykt_EfPBJa+zfJZXgD>R2M#SrbTk*A3;>*Fs zIh#n;gJ2)bZ7ie))gqCJJ{Pv*k31mCE*uu#MiH+dMgcRD;xiw&vMI>wK68ncZGtR_ zsE7kj@|oW*RBfp?;4?qBvH@iMKJz1$^(Xqw*Q}Z})F8Xf%KC!Nus^|Pu8FJm`pgI7 zvL2uL1Gyrguo)V=edd=|){iXqG>5Eg04?}&pV4EXE6jOgR3SIedtGBU#E zinm5~a2=pV;**QBV|A@ZO$7FZqw)+3y9)AI87HmjiL^)77l`*prStzp#6L$BG`9{f z^an`4VXVl5B~Ihi4G^6!z79C6E{=`T4pF{(aViG%;l+8e?!A`~=%h=|0e$$A9O`WQ zCDz%g9eJ}DCi;#pVC%(=qeE77(q+5AV%g|LySK(lP|( zq0DAIp`j&*nOi9srQb{X8RTZ94w$Va7_d-MbcI6wBMIP8UXkc|#TD4ci7OsVQD_mM z@tV?8try*|EM!N7IW{$XUME2kV_QGfot;yI1tD;TTQ+P&C`&O03+x34u71#{)j!%4 z#bPPM6)R-IORz5I^Hbv2E3-gr=2gwvDN%gYv@A(6YzRfZl%wUCWjdjAE5)l?sx7#DqV;(;h$Nap3K-N!Py+_l)V3{dK$$WyTibF%se+ zS!8}Hh1l}9g?Ow%h-(`Q5zY*J)J|6yV&K<|1bU0F!m+M%;Q z8vS_wy1et9OvH;g>R=ABXiQEn>Eg+F;mV9H+~XwNfwIV)L+2yr?+EvJgK(EL5^e^V zzg#T4enNv(-Aby*A=N^7iI8Z~f0roXIY)@|$F?1}_Arswuwzzv%!DGoiK?VL^Z5o! z(@rd36=M|!8CV7-5EXAGh#(+H&qBC;b{jxB&*Dg5I{u=~WA@gY_#!sC0eO0j+X z#j+&ViIe_X(Q!fvMn82zZ1gJbLcwDbZ4OT;4j-YR>h+OG1T*X-Tz$1KyWyIpQ#q2f zo|=wXAzY_{0t9gu8}!2ExWzp*)l6^uxeRa+U=>vKrBUlaY-Jdi*#) zcbK511d~z)E{1@~>u<;l_+SC-;o4iHTA~jxJLStqpX8 zf*iEMBZJBnBBB93dBHhFkWLvg##G})#%Fl1K!}0*CSq{>;WRwtW#NiF+1B;kjm)}97yQ>~Wv;lRtl$qs zJ};O&2H}M2$%XjdGnst6FDJJ|I(f=s78Przg#Hf^vu~zc4d-asP5q1iLHswI9W>Gw zdFrrz30Q2lH8;@Hc7@DSGTzh)S8imf*mYB3;z!ihkLxqu+K!r&24~o)6Fen z{@uqn=LZj}I1*jsyN_DXPMIO&$5iZrXT1nbZRa^6yQ>$Yr*>qYi#bz=gY)M(ab?rm zVftu4Oao!0XY zM*DA_o}ahjQQ$J0o7MERxza>4_fQ{ZCd@~Tcy;3921J}I?+xXU%24PF*EgrV)RTxAD(%R3EDif z1+O?P_RUQ1W?^ovfjJ1^kRf4)Mi1Pyre3Xk3~x}{mq^8RB5PKVy&-zf%FdN>4_FkG z5`f{5;12zD3I2q*b=DAeT-43F4TRuW=c?FdL9PTOVw}K9$-o5r5rGNe=AMkqlEv+y z9iSC5M4LM{D7%-+8kow6KH>7J0~fpyyTUoG1FG@xt@-J+kE0_yU_+z$Q8^kIh^-#RRwzNJ~SD)P&Sy$*A+Qbaoa*TlhFI;BZ?USg68!N_HZ2ltk!6S8K6$*d_Rga zx0QzLX#BP>fF2@x{A~bQ8+R&*vJhfcGL2geoNfoeFhkuO2!SEEWCe+xX8SUfW4u=@lV6(8xlVFJwLtqzSJ#&&C<>LW8BFZ+< zwIfL#bs?u8P$;kq6VnO| zEshWV+}$r@b-0v@)nbL%dgq9aaxa4jaN~m;EQ%@&3z<;ZlvYgx_oYSWKS$5OS^^`M zKHFfYMe*$3*Ka1GELVxvV26pNzF|Me6gC-)rKNb40;iP~f~1(Cii5~j)`C_bZ;UEX zbFZpTbhFiLZC29LUR+{_X0n0pO|J|ac?aYrI_t6{ z<_2iRnG6;P+-5&1gApr5eYlxkPjI@tFNa%r`Xj;<$zzX-c9Aw=nvEnK`=7z3PwA5G z9EeuxiD0-i2NX-CUCd!F;9;p;@idHR|BB6DIX@FW6qTGOu zbK>5fepK`;Pd9L{RGJgaJAx-bzynYL9Ts~d>Al=^hfvBn2mZ06lBF&T6Cx(+;tK2)f!Qu83t}1t<;_{# zqEphNRfpnr5C$0+e=KDm7r^nBCV?gu@L`W4kFDvQ40H_M(mNS6Y8arBITvCE+&8Ch z=8t4N%@lPR+~?GA?k+ux9io2DO#b#^acM;l*s6sUnb_%WsOZJ_9TrC_7NBVQ+-ko6 zu<*^BlX{wF8ErX2q*ftZhA~fyHS^k1`@QovrJp`x*J}ZfA7N_P2;ix@cOvkdx_2PK z^{X5jI4SW29aLX0mR3pxuT{1S)Kdj%a}m0%`KdCGp<#>r=Mt86_m8t1LeZ#U+I-p2 zoPSnBamW1eL~{N7i-+wejG)wk7Z0e_0hx!2UZnQeN9_8t5Mot^V=`XqVKd}Dhp3R? zAP9#4h`4J(4uj9Lpp9Q*MKRRAUc9p)H)-urbOW(d7n_cXpBA*W$3kKPEu9}oE!|8& zh}lFU6%pKT#Ch%pRRaBnahNvUJh1VDjjowRT%xl~r~)B0l}E+B4|Gkgpb~j|fqFYF z_B@c&yi!6rrw6cArBXF4y5D6kI4bzU&KY~d>^G%Wv%xNg<NjAvND4bNw< zSh%Q1k?b_f_68Ja~c= zoaNA-Z|GC23i-jqVs%yego7k%d!2$MtCI9cAudo!6CsPQ35r;sucT1KkJ}}PO%R-e z2vJi338l*+CGl*O4X zB;8VdN#E2cpsI9~O2WNx@gva6FBT8w$aEFU!@u3R7buA&a9*Cs@g+nj8Ccjm#LrcZ zBF^V!51?q9(3!V!usFiqm3B^M`IGhDI}lm4kC8}k9c@2us!?my@cR`MWj5sf)ygqsR)#z>JVr9E{n{k2egp`sSVhQSo{R>loEm6R25tfU+Gn|ua1mUc_H zlq$n6@5@y^&Nq;5tBLnduWsPIJ&?X@TId!b=$)n**fC{I>$CZ}YE4Y_<>2 z#!+vBYJ9(*I68Gh14mt!YMj|HiR~1Vp12h1wd08^2}kzEAu${XirVUR>qf$Hd}9L+ zTPl$!Gps@5l}Jmy);~G%vUAjnZh%-;(SSOrnGU6})oT#ODK!a#Jx7yNW6*cQrr~WR zch1s3LSxV5IJ*C~iRd2vRC!Z-CR=nvC4J(=ld0)(6v(ZJ#mgp7x3u+24hq^c;OTSp z>ZhlrUfuDG)T=GeY-Kydgw5-9DQY@-$1Nvpk0AdobHM4KF~);A7&bZP@SKBj_@MGxLw z#Y_eXAj5&Z1JvrR9NM{Zj$ggNRBLaNPdKOW24uA-qk|Cgcp{a0?bP%z!UL zBEUP^G6;`W^0z|ZT!|sf_=KA`YAK!Y+!5$II_denMMe<|Eb}{_judpNDyRWslW?!}^ z@`CJMMD|_8x4t0W-8a;;Ulr9D?`>kd`bDw#{ZSq3UW}vCjMPxhdU=_&r8_px7_`2g zVwJx8YA*e&$$cAM1{C6mPDpR{2cKGb%t`(0n)x5LW|@u9nAH*-(I|kw|4|qIL%DDt zXpZyGcE_I9I8{F~1;?|*zb%U(-V00C%MN)m)n@_B~2b&DAAcLSz){NImv zP;&{gf_!`)Ig7mVi47QCt!8RoVRAY36XKSGuVx=nqoXJ%R%B8X>P2bxsDE7LeYqC> znmcO6)_;uQn`=aqPX_Yswc?6ThVm7)V%;Yb(wEcdzzz8l+-4FC-Y8uzf}aNYOSNLa zr;~Ygjo9*OJI^X9wBzElPiOJ1HR6i;?%{)~NR0?2zv*J0Fk%KyX;t9yO_xiBiQo-( zu4L?STxj6uDGbN3>=4c*=?D|CA$t8C2Y*hS8uDNQ88Kc0mpWmxd{qoEbo-KE+%Rtl z7&#I7@RS9^i3o=v42NJdMMXSDBH|yRMEMd7-NQ^&tp=geWYf#&q!G~aR|s52f`au7 zraPaB2D~5yOt4vCWxr9u&#CBTHE}em@tU)Vqy##1O(4uzs_{Y&!v#od8j69SYo`D~%xToUw z>FAxpdm*Qhh#iIugyGFP^g&3_HF%BlZ!p|BIfz{o^Ld+_rTQm@_FlI=Lowp0(QMN$a) z=r*#Y)rpGrWY|dcKwnwV531dkZUi6*8M5;mZc=Lc85h9OJ8OVJv@%TUW&}vB&^mE4 z5D=sbdq_+h!Y5yFBOn)mY#62cc;()0-Yqe>1|fFhHt(`CAc#~KfhIgcZo7S~6ZC)} z3k%asw3Jqk%J9PVPe8;9q|zBbhK$_+;UXn=&kQA!5+~Y9>;#ZifuFdUiB6Sv+iDFn z0bM2&0gMgPo{-9)P6)eft6+1?M;rqSLW%V9GUzA%Tl_-ba(q6?E`q`yp9S5DS@at_ zAt#NLUYxU7ZB>J?Smhv?96K8ZF#LZ2gIN@_Rvi!mn&oa{5^g`l76y8m*}C(HHh0LWApo%Z=(@O|j>JMlf{=rUQ}R3v%+_S(Rw{&uPPAKcj&+K1kv;1LW-xQ+XPieuCB& z6w3F1ad8WJrD45pC^oB}$8rT(+Lh|I5^9B}A$;5GBi^*ibLI5XebMTu&M{=D=H$fncw#N12`%>whD z9rRqs&GoNR;zh1MFT7tDc)wN4St-9 z{_7yFXz*{gL7Fu$eKX1dPbF~TPyFRtG4aIEggtVB$J7(oeUc&GKhciX^)n}Kqs9C7 zZ}&8<`~XD2Ct7SR^Y~Shn$h2V!}!)((f|8VY`%Et`#W&8Ao+)$NDuj8SM0|{7??@U zmPNOLJmwbHzZIQ+oRsyt>=#}~N+o%intB()VZK%?p8avM<#)VUD_Wfz!gtk*X{V&a zQF}@f*8M*V`R-b=>p!jdhUdlC|LM+_iO^4Z{9tW#Q8H^LuKDRSeD$k-o)D;~Za|3I zChYw=H%0m@ale_cTKxL+mFK`U6SGfy!Kt~YZ({F@?@ovCo&L*p_`dCzw)kH2OF_D& zXR!MTv{;yJuu$qxh(o{3;@B5l{_8HbQ8Yi(M}D^wkuxjV#)n$4pV`K3S&a2z0E%A0 z*?Rs~EryV>Ez7|YxW#Y$x|qdp{ODP<$c3NUTe2<7&CakCi=9a^b&j_6vKhav0PJM+ z1220g1`vQqzKK4Qz$$Ya`M=}?P50?|`^%Pi^qNE# z*so_88XOMwn^v176nqDQ+OD9Y-zBnmLw`TRjl zZSseAABrXhSjhPUW{c>zGbg$^iKX!+hoavkv1ZXvlJFCLRWf6G-X`79S4O)hvp+$d zNOdfI%8tI5jOo=S!2XA=kCq46wegO9@93@o!$Guk_51zby?fuvi4M)ABNE>`*GIo< z$_o25)pRXKqmQmN#rNAzO-sO&;SWjq$MK{;2mW06^Wu-{+|fFn^=~E6Gz;1OQ*W7a zgK_iJS;n|2Q)iAhCQO<#J`v^HQJ)swoWim^<7dnWCLYkD@1?NJL}U`R)2M7FE8UZB z4kl_j(FG|imz6{}rLa79U34FE-UntxjeAgGZ3fMb<994@?Whng){dfOX_nF&tyEm!jshMuhIG(b~)Dr(VorOVpbP@yE*I1 zPA_f2+OWcH`7PLB#->H5<+9rnb|vdtPc->8dOVl4Zm^*s>_&s(-eGjD!TN9e zx4|miqW~p8oo3uJbJn;{MMYyLbnV%BT-WQbA3I@Oaq)!i6N)=`?Kxpw&+$b)yLFq; zvuF1kx)*mF-^pVCxT!P7cbah1tWGygy+O)gRkW@R8=RP%p=&8X?9GTKz6{H^r^>_I8`65&1V-Ro<`O{HYYR63fQ1NC7DVkC*v7Y zan#$*?efPl4QWR9LSwsbb98nAWV|!FqJWLabY|(A8xV_oFxu#XsUn$d=)c7*Y^D(U#p6o!pMi zNsnj3%vm!m9!CGwjum7L$WiJ!0#E9Fw#AKtoM`9vtV^g0~b7#7`ySl2n zx~jUmCx?G^&;P|;f0B*e$)Dzo#l+zM8vc1Wi{~C5M3KUUOnl0Ei<;BG0kH7 ztk${Pct)!QEcF?_fw%40p|GOIO*c34N#`DC>)AQ0SUtP_adz#MSC9MC*lVsD(`RJY zDt?Mxwu4=K=^A#yt+Q|W^KElRlv(31dWfAja0%->VEC|6kFvo->)2xU2@fS3ea;TC=Xo{%i7n@U;kEn-JIVgdR`50a zaeg0vk+0?J_#aMR__M&*$-BI5+ z7nOdO$&Hu9>+W*`FH*UbA3M}orI}hjk2fSF!1^a>7RtvCiO!zvwyK^PcM$IW30$}S zt{Ho&ucljQNEpO)PeG#W?Pr8aGhP(yJb|FyOgCz&vmC@^#!@QyneiqeF| zI7uh^s3LkCbh1%h&3TaB&MQoYQ35V{xC5-x3RYS`HF1)=k1#hYjRi!5`Xs&Pgm`w{H=J)?erfltXooO2+~!H z4ItGsSpj#KVI1B}d%raJ616xuQwg z4ztq}!TZ>37FNX5dhD>iY_zj;{srBV$ zd=U+GY;Ggj)->LO#0WG3=D=0K6`4Uv zCmIk(vL!LOfiO`w;EM1zOENY<8susa2Y!eG8k1-xa|c>oHm&thwAw8dt;dL{8p3|0 zsxe3yYH2vlie{pgn5a_l8k-?v!m6GJ5g7lbp<$1RZdgi7>#31Gu}VKzYIau1!*oU@ zuSN_?$-~H#gNu@U0LcDO_EJo?z*j0-CEX-PhaciCB7GVMdXvwm(GMmmm=7+EmBfyp zv|kNsNpI@RLr;y6gq2_&NkAz9P)83aXMW{r1Cm$`K?9&Q>8kS%)!sQbsNm@la6PLG z`&!NVU(BMP=YY)CKIn4#q1ful2h_}VBT{v1~e2wI8)0E9ia#k z8v{1uFIA#{a!&9Gi3(&U=}Dv%gnk3TlJqpCK7g1mW20<`z%5B{X~T_8k-iC9-;D>q z`Nt>Ajvw8t=_pk%esAvkO)Eb+EK9Gwa^K63ZM<{AN17h5^*yxdg*!t_*VH8It;Gjf zty|E*a>cY8ed9g!e(BH$VcbO^yG%FfDcNbN8tp>c$DPrX9-f99R(6i$+;a@))Gz3*i0=De8`;w*@lG#pv6k&hPDTW z5XCJr*dj5wMUc;(*YI+Siy5B6pVE>&CAy~+r<`02T&27ONU+j7;&E)Tn4Qv#)r+ku zgV`?eYf3%~iM-S+vll7s2&V$>1d8yu6{bY2Ol{Tgzc4<3WP8M4Q#+-tCjLr!xy7WV zh3;GBl}5cdk@^+;Reaj2Cw|Se066HE)`|Thrl*xAJAEKayY=?8HW}a1@<8z5vW_@w z8b&$DxOgC;rAW?BV}BI|*#Y*LI6pfxZMBp*MHh}aGc|pyOFaK#is+MB5ZrJ-=(4!c zAO%6KtW6T+Mi*FztyD1XcCaX;GM`AWPO<4dwH#Bkc85FUR9efLcR&=Z`rJ)@(0Gq* z>;-nS(%KgvX>F_&|H;f`n?!t8M)0GhL{^ML7W(-RQ5mXNWIRxNm|7|V5r&(PvEAyR zMB$N~TgRKV!qCP_#S(2H(W{fjdTOd8^fpwiI8ur$2UTbkbE~MUt;?7QZk34X+3CUG z@@~thx$V)Oje38G-lcg|R%(GPr`T2trVIONL%H#YDU%5F-Wsn!WwR06Qg^irGa93Y zY35KHI=1#Qq)e*(6O$twJD=LviH&V?M0#KZubC?*1&T&)B(q7oai8fSXQbt8%O7Zj z8f(ZVkfvw_+F}BfNdWeA0NfV=pfuku$pJQs!vTMijWr=g!oC#gxjp&(x#FVS%0!zY zk4?_r+>ZSCJ>sX_^Lreak71lZ$;yVIu($3CiM=E|@F>UZcemPqHFRnn!`Mr|$?#m8 zOIQB{FP7A4T#_ej#wD4hW?Z_cbQ+hz9EVF+n9I#Me&X_toLeq?D7gyqlYD+2St+Wb$O7t#6cqLpuAvmX0n8KK z8s`jYEVrLq40~^vwVd$M_R7^s)2xz#3CND>s6#hdzvn?&KOFHzJ{o-X<(5xk27ori zp4{SoxFPK2$ zGCplVH*!pxF@K);sC{ODassk8CK4o!q+}Pv{HkWH^D>9UAg!QTheDv!?}>DYL?ELu z0L4~*`9LFJpv*x&ky1k{Y86_0q^cejx8)TS9%?>4T$MFSWqeIlM8RQtF}@P}@=|+y z5;SR$q}rLDtN>YofD6(m5z34fCc{ttumWRE4MORScg^}bB>ef^3J}{$4TW)7Bn>X+ zGM<>Bxdi0_Bsob)9&vkqT5#DC8hW#8Nc9)c&qb=M>VY(*niW(a!-vt6p*K|;@^A$3 zs!A`Fe9o*fze}nS(gp}wtpi%6b)1B%Mk0F)A!-5l4d4sAR1AbEr=2{rx>XvV6MASY zn9>G9uh`7#Gzd&i)Zln`s|m+cP>nM_b@T?q7)I=DT(bBnVn3p z%xGA9h1IERh8<-9kBl)Oz6VLC{9F_jw{B_MC6_WOfSX(lE9{^je+XPzC>af6Ug5B! zy^?g0;CAw4NxIdzf*P4tJw1(=rSS93! z>VV(ti!RNvM?@Ffk;y@IAnT1?mMQ)@B}@2)j z2mrqN)dagJ*V#t#x6)j{8Yc#GN(pXT=w^(S*i-Z20f!w|R+`YvVT)m9W$b{sv#evw zAMXMMh)EXJ;AtEs(TTUam8Wb{y3ed^=|N@gUF3Ez^s5Rza*T4C%DO;1^m0Em zyi@rV?1-o-@6A3JFO^@{=dkoIcFxFZs;0pWSOtX5X(O0lwY+CVr!tO58P=}74( z-nf%=98KZRaWr8ayc1|jc?zvzxepSGUv<-$9yUZbXFqj98Atpowbuz zo7L88Qmam+R*X(MCdtjV4$%{uS5;AbR`sRuP1tp>0gU}R!3+Hoff&R;Q4ldY}+iygn4jCMPaSYP?!nLA7i@gV9#XGIB9qT^maet zry1uJ6p|S5gh&F)tOjX6vKo}e%tv=$j!La!a)MX^*%s0#I&gPXvJKM!TfEl9Ygq_g#G-L!ln0s&qU_GiGIylM2%SJ7pQ< zr#ShkN#_mEaMoXxFH?R^>^m>-8r4w+^|nvlTMJsrr>gyLfwr3fM7+|?0&Q0WporfZ z0f6`ocFA_Bm-qL#3J*iME1l?b5q)+2r+3~&+)>)Z$w(m@^hYEe?SpN)y9^k_@184e z8_XA-mWDMGU^*E>hz}-FhLaHbJ-kY8Mkw8?ReyRWUwJw-(wpsi;BmF1x7v-NE=+ z-TLlcH7Hg4bnE@7qF1;6W*5^?8>3r0>|#8M2*kJ8#aI;G7}PGtp$PA=&@K{Y>^!Sg zQMVH5fQDPWE5(#S`K(DiI4BpAdU{a1*4w4bW8q(E?MJzjDzCW zVJ5<)oZ)?vPIGu--0&*)pg1(Vljk$)ERI}|bw-==5%-ka zXADfcTiS{cp8(%ASNuGpptZfRG#;Q<&}fQ4Ws4YUVO>z2Yh#SwmXJ}QRHJHad?pTG zkb4GcEk;&%JX_ybn9HbPV4uyH$u!stBWIr`VKHb_0YpDzR3ZCNEFYE0J`hij8p$3O z`h~qBlZOlj?ml2r-xHT#*x|BTvO-o1>tys^6)QJl5@Bu%c&)F@wZs>Wy12Cj65Fbx zE+va7b4n&u6kU|jaO}bhS!sBKN>Z@*p}c}3OSwM{KyB2PlqVuHfCx|;J2B_t)@+?v zdhs*_5%HI#BZz2s$%qu$pOymg-lA?bSd05aOdz{PkYep!5WNpaTd zCP;xoE22>r$k7pvD@Dnrtp`YuRa-~0YHQr1IF@^UwJ5M{#fq?25*l(jc$Mjo2gn!u zxmD%E+Sn+>r6u5I_oX6Pb%R6kBAkPbUnwSDR&tpf#*Ew^GjSaI8~jkd!7=+1yHm)I zR8TlA+leEWojojapBWY*FhE!|^z!lXdnuC(Rlxb=39;+)^x`nla7&g~`nVUJ+%G4O zx2t*X*L8*C6~L%W%ZI&I&nq73XRAAfI?6;iiyrC3|8}RI`KR39@qU;5sY7r-%}FF* z%2gRtUCIwqm6Sj}KS1vkd*>@K>?&pk;gM`a;3jI}M+=%SSs(>0RXxdKP(XwzmTXo^ z@}0zt#w*0BKMio!DUMgj5{e5)7kTZCo2VImX|RgKR*H27opbbVcQo11qN-_ST*2g^ zd#M^~R!$d4D1j^Ah|E0>BUZ3f6{0F-H<=Nnru!sEF41&l4-vYuO+a=<^k(-XMKr$Yy7r0_S6%Dyt~T16#N;s+ z+aorPDN8;=tI3HgcQITmWaqcM!iC#e^6VQou#m)bK_Dh2su4F^2r6YvOSiLN!(g=i z&??$SA@rmYHxWa^EK}alkLcG;0U(Z=WfUdY)va>5wCOPJ@u&b&DLl;RMg*A%xM&Dr zUYsI^Tzzf)>fh9ViopI0{b$!i=|2U=k*KZwnn lnnJF`cKY2>32gTeOxab=loVu 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 diff --git a/lib/wasi-tests/wasitests/fd_read.wasm b/lib/wasi-tests/wasitests/fd_read.wasm index 227157f989d22600259de2155b956f82939f9f25..799ca164514ff844cd4ad08a7d058ad67ee3b97c 100755 GIT binary patch delta 20593 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 diff --git a/lib/wasi-tests/wasitests/fd_sync.wasm b/lib/wasi-tests/wasitests/fd_sync.wasm index 497b63c9bc8cad35234ce44c87c93c0146d00f23..5fde9b6274438e9cd47b346663986cb9194e6657 100755 GIT binary patch delta 21732 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 delta 22456 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 delta 19722 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 diff --git a/lib/wasi-tests/wasitests/fs_sandbox_test.wasm b/lib/wasi-tests/wasitests/fs_sandbox_test.wasm index 3f0889850696991bb09928881ab09172f823c1bd..8a8c6349451bdb4a862830a0873f85d676706eb8 100755 GIT binary patch delta 17028 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 W{`5@ouXMliW<61^mM?Y-_x}T2fvJrE delta 17960 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 C?FhF3 diff --git a/lib/wasi-tests/wasitests/fseek.wasm b/lib/wasi-tests/wasitests/fseek.wasm index ce68b75f05ab4c1bba8f39d544e1a6b8d59b7ff1..d3a7c8f8494a0c9ed50f18eaed102981eb688c33 100755 GIT binary patch delta 22611 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 S(iMN0f}6WLHr>G1sQ(YKwL}L1 delta 23535 zcmch93tUxI7WdibzPT4T2q*}`xfc}hfhY?2Dh~O`e3h2HY%Db^tb8_^nHS%fXyi7p zCMu>}isE#jx7)6w!RBzNs>{KdZKSsIi(17SR1EQSb#?Fw zw)|jo&*O|K2J=pii`5e2rzSk5woFRy@UYru^q9@+@b+J@5Nr1UTgApLWmjA}=<>@3 z4;e79?M3=`>?kXFob~L@*~PcsJoc8`N_(}=9eT-p)+xW7b?j1D(5I61=oXyI7P7o~ zta#eJ)9;&MJi;Dj>1)|K=1}$54EmFC< zR6WJEst>8l)R6kDTBAnQthR69x7$98Z4r$XQ|L@vMg>39UgdGlq~NmzDH0}nnBy)HLlnQF7Nc^_ zEOd;P@73~MS5W^20f_aA_ou1ee1DwYz2}3`6>|W{hKPZiBHo`7KoTS(M1UQgADhMN z5;8g+6-3z#tyH&Vt8V)7Y2Qgob*k3BH+$%%nRqMX0oTA_71aS-fHHiBU6W<6s(2Ts zs%ntU$e^x@QO(8$6fq2w8}3qLPgyOhnYM(QQT4Vc$7&J{>LOS#AZrVVDd?1hO0;Mp z8l)Dh#r(GnAHTdsjQM|ekoqSXtZy{B(|c-xnt(BRr6o$CjX-3F-*oGZnv&2|&Io)0 z{Untdx^_&WmaUdEg2*Jq3Kn1m>g75!^nTIy@Gvo=JV*?tdF2q5hUBOftk713o>i>W zz*y9ksD-FS)v=kiq_pMq4kGFOb{b?HQA!KcG$31yF8>v>;J;Bzn4f_zv6yHqIf<7_A{O-FS1_B%`qAR`t;A}lV8Jn^ zG{>d{)IwVs(^U)|8tuWDrYV<%2Qk>)1m(W)xTYwNYM}g5bo{R<$GF`}Y4B{yA$vjj z+~9>!P75De(U|go$? zQa*3Sg;1_FMfvGYL!;xv6#OOS&1h^kR#cGI=5)C>n}^3WMLDd3wKT8!|Db%IMY$wA zD3*Vi^3E4Rcw$q8zt?$a^aa?Y78c<|_ZYP}C`l(BlFOti(pxr=j)nE#OTCPpwa^h| zB$R3!$VREfBod!+zx3t?YRvQxn6#ReN_Rm1%{Z=<8n8xW{s?!{Lsc3|n`tOFM;J=8 zr!u>og}KPZe-GLH7Z57c5*iA7QB#tJ1-bqB(w|SQ4oll-egv!HxUbz^qiP=}GLJ7&rR?^%BD#RfbC+z11hEh$#7L|Cm{KAlh2+q>K|FH;y=U#k`M6lt) zsQQmY5EMbx`9-k(KNUgkg&`YkVr~B~MR0!m*GL3)7e>{Eiy+vPxjuUpkh!j>xzDo- z8X4;&7l3RKe&l~I0)eKmuEGDrKszB5QiU9Fn$%Tnv3`9^qTZjPCIKvPLf}|l5 z?$wOujY=ADE?;A*idyoU$^KxDT(sQe!j0!pzu!&P2UmLA7Sa1iIoK z&(vTB29(i;Vq8Eq_m0#@`-!SWcSIEbrUIn_Xv@g7BeG3bDdND7PrIMM>zE0Bu$iYH zyLQ|Jfz679yrg+Y_9V}1p1@i2T=Q*4b6;?UKu*=wSZ}OA7x{*VsV>&rf-&%0$KFJ@ zX)8rPyKay5Mk^(AmVGkw)B5Vqk0@07eg1*(X6|44-Rp|ir<8oVaKoVoAFTYi4HXVQ z^XlBt%Jt=O-uGRqr(wTb2byibjHf62`kq)=3pOxq6?{5!2H1_$?ij?DQ3dE~*s#yE zYOr%Ev}x#?jr}|^Z5E%H9Aw|u{FpqPHUFNl4cLvcvRw*xwqB56*VgeHQaZ-(U53dD z)I5wrOxYffJ$y|{Pqv!xPwDS|lHenu!f*VkxzFdbc@5^rCRm%xhos)nX_lNlTg?vG zqZKc}8jW!G+r5AX-)2hF&i$=Auv2_Ut3<%Rxz)GqTYg1acl=hQ1=u>iDXjzhhJTt? zaQP`>L4jICyvBZ5TTL_h?LG&RHh3_BhYwSFb%&v72Z=t!YBt(RS(6C?k_IqsJ#W?G zreOU_05zhuM+ulOj<~>#jjO2AZB}ZsvPx8HW+g&a>bX!<#+j8dvhq|F4UaV|qh;l{ zqSET=la&X9qSj}2C2j%ehoaJBRz}In*F~i@y+>B=6qQkCPq(bxBq}YET(WX~qn=J# zxuS}KMZ=ojA!`?lu3i%;#6>vG6O|TAY_jqX!8{95RaX8aDy`u{ubAK%0;L0HNkCr7 zmuLH9O{mdMQTGwwo$Y5o^KY_yvO1oX(>v=UY2sw7Y3>|wM2F0GyJU1talpygvwum# zo$9Y;JTEiXq{7h$`7_6vR5;G0!U08XL zZ`~e*)wUkgwR#>{W$m_&R4kVBldAK@IoJ8>XJaJv7a8I&`Ig@kxV!BQOuSvQ+-`XY_+%Fj!d<`T{4287`uX#ADj@_{N%}gp^<%I7;GIBWU28+ z{!GPu0Ae$$9}>+9)xpW5%a`A5`P|tL2oToP$xf5lbUWD;njY&{1Vc8nlZ|EqP~BFb zw%$kt_)tWhpb1Sn)79=u2B8gbiuNNv)Gmqrz<+O-66HXRN)tGEdi&-#{XnWk6lnpt zg={qe;Z>Z7?iIho*ck$FKVlQV5*`*2`V0ja3d$(ZgE8^LjW9wgoA4W+vfxi zH?ep6Ni$J(LKrs-F=hYor1dr1=tx9$z z#^7`yTfI^a1usxQutg&PmymIyA`ZxxDTPuG$hL~k<(!P2rr{csrJ6m22_G`{YXD1Pozn}k%-ChZVw0vLn6zI0f1eae9sAYpADgl+zPE zOFH*qRlK}&W><3wM4m-acx*)V4=5ylpy!PZs~ZVS@pj{{B(~slJH~nIRuEiJrd9Jt zIu6QwQLqr~v|A@z7<=aA&GPy?_EJaQX<`e0cU~vUvYANm=kwBl-3NK?8(3@ZbNC~< zS%`Aq%++1xvjD+Z$B*Ua$D2_-ZD8mSj&zV0bj(OGiL=44OTO!{0E+k@UzM2ZlxVj4=Fe3lzJ|+Y#2-AlN0=}@`vXZx)E^MQa?FXiP?EXhR#WyGP!c%WBj$p5NdeyHZ%y{==Q@_+W~$=>I&7u|Bv zX5kIYRI*V$2M`Sn%Mh_u_4%9l){9!_oY#q1E`+NW4{v8Web|?QU~I0PUU3Qu#K z&%U^8?6Gn}sfAHbPZ*##E-q+w&cK1UEY8jRm~_@s;7_Q4IN(fka(i)7^Ex8ZpkoCb zDH;`mqbFzbhl?*#%NOvEi@UImJk}_3ZCyaq@8^S!9B^)`QIK`yK^j?L?4zf)UC!Z+ zr9=h1g|o;XOQIhLhVmug^Sa9?T?v!RY_-dfY+6@2%Zp5 zgTXhj?usY~eOGd9mDCb&lmxFJvFMHxHXX-lREc+-1+&Hm$Jk5UFba)bf-5HN(&q@c zV);qkhQ|ZidsJJv&24rs!xnTgxC183XhE1>Uju z#eg}!cOqNG=l0Hlwb;~qbctB=K5VHS#5%0+RRkx%qGj}EtuwS)kgUaHY!-S}&qwqb z5xYmAnQH8$C+S|Fj!o*XO$2z2^cT_AaqjP%RnjCqIwJ*#66iKW4BZug`_&t#-!A&qSi(j*R@Y?ZX~I(s_cDbeTYo;iMx z&*??xiLgizbY+(!vp@(_ypw0W5$Z&NLsC$SD2_-_wa@s{eqCVq-t1Qxtfj=3l~UC{ zkg7!rVkrTTZOCUusGRO1{Z(`zRsJ}(2cF0M40Jn*XvC2KV0s^{I$Ew+HR42-IB8;v zL>zzjQm4baUS&4^_N=5^jEu0{L{z96NPu8JyR8~n(tcJo{mf>nAU~s;er7{Mh4eGk z4HfV+%gvH-DJ%K3{{F;9OHm`=qQbXq?mr~iT2vA4N4g@ObXnFYIZkY@Y^EDrM_!DW zA@|=oN|oj0q|W6iOB*UAdKC>7KyQv&GSPeFG7CLSL;Ex@p@+;R|LC$wolL$G<(ZHd zD?!n-OGeb}|k{Z8gU_16YFC92Ac#!fo ze$arOK%Ccj$1KL7sCkW@X0aKHKw)D<=NPZ?a71gg*H~m0qtV&tHBK)QkbO~J;~V*E zB%%eygJ#j|w+DS5uknwFX1CXPE~4o28mrA>3k-I8jU{H$hay7y1!mEMq8*bGmqAVx zipU&)V-{&*n27zd=rv*}O{^L{OZnD8*=#%ibWjGe!)$QtR*w?5y&gDG+6{`_`kN0t zv3AS$x$kZa@=FG{XOHm-gA^`NM;|#fP;AJ6{+VvPAsL!D-QrRvwQV z(w{xSuOG6^3g(&6jH;T`Ly!=vs&QS>hp``O1`Um4tcH&qmdEz;%3=4kHdVt+Y6xuA zV)A-+-8Kjd6Sh@*ljmNkBla0`WiOYt?_GIi8Jo*fuj*iKCGxIL3AatXYGI)XSLTAu zf*mW_h@x$q_NQq=k(+a47Mh2uf8pJSw@o#3;o52Hgk3L1hN6QL9m;~uAc%C zwZdI!TkZ~fF4b6$DNfC+g^e}i$*_%;wv-oNmt52Hx?wCeynQ9o&0VTmOabABdj8b) z$!1&(yGVyk&_5Wg5<6le1Sc@4=ydq{@hydZL7^!FL0c7@VVh#ubtg77cZ?VkFW|~k z3*avH!~ES5ZMq2=7-UJB^v%-znF4g`F3Z+v|KhnfbWB}W4+1GlBGg5JI83Nl*YkUB zNbM`?jKd;RovHmM0f}v`Tn|W2V=)-j1c$r?GfvPkkXA-L{VIe6%e0bzazh>h8{gk} zGdT>rfEOa_G0&F2b-YH*gVkwSMxFg7MYN~3ET#Z&6|x%|AYy^!N4#ic(@~B%`e{hi zQIu|{C}+vYvBOSLQWXM7LOPJ>5WxXu+I$AGV>qNCnn;l-141%&i5=5Qik+ovgJ)Q3 zmQ2qu;6}?cUTf3Fp}v+;mgsIUL^Vo7#@rOHye_Nvg68 zX&0#bsYwKS+3G%_1c(;0Wi_lQxB=fUI#G2!_3)zyNlX+-1q;-DyzQvb*2={p2?S8Z zSB}bcSDOomzc*@l*L}p!0<1EqmZe_1B2fd6%O(`6vQ7ZrgOGJ}Qv2N&W(Mv@iUJg@ zs1$kyr1nsw$fr@Mj#rPqAt3r7a5H<8cM$MIJu+h2OrAbw2%E*nj|s3B`I0e3Y$kte z%urF2ZpZoHi`=+*j75^%$X4;1n+;aYf4;deZa2|lMO`1M%)vVijSrHiw@nE+O8rhl z@#93t@3x4wfn?pOyT=(x$XdZJxyDhNRfo#hOZ_gLnz? z0W-P5C5ezm1+qWX;zq%%yWxRoZo&nLSG(?_kPuD@i=A*5^6ZL3U;`Ty#IjnsSQjqg zOyE^~=nlGQPoX2cd>Vmpp$g=&y!er^lZUONRU**3fTc!TuM1de&)gER)M&dIUTTML zSzTZ{t%jvW2vbx+tJ*RpX9tkmZ|!l8#7;V|xGm?LiJ`%zS7JN2wlojFd*McR^PfvI z*~`4;xFu{ce|lWtKgc|s7Tb`AdS4KZlkb1>s5|DcgZzOzvH*759cf{QefW+`DRGc{XIs~90dGGa zd1o#=#24Q=!CE8MIgD?7R>nrk#A;8I%_PMj)|YC}P!akd3Y+-w@&35wbUZu2<2HiSiqwOfd{?Z?)r8 zsk0oL8@E$b?Pn@trw%_+=i)PoIXIt^ICm7>Z_r={W*t~v=e z*`8x7>HvwU#Wc-!AzmD%Bgq2CZ4+KmRFY0mkJ@_v_1zhX7)p`ObHoTUBG_5a{ZswH zBX_-=)>Taz>cO6YYd!{-7b~gdZJrp zwdhuaSGeG1lAn6}Gofv78XDwNP3525lW!i7 zGq6RNdERPT8mr|!r-jZOZ@?J&@72**a&J#|oCohslwmsUycv`NUQi^Z$Qd5y&)l1u zXgZJ_p_RsAQWoPlKX`BNw2efSyu_Ait_qddlmHXBbR{>Yw`0rr9n%XDC$FF0Vce%e zFPSB)!z9g!P)?R1So3Vt6x`YHN^NMyw`pC zB~KB0a3a=(rXELTw&@^LYDhRaXasQ_3Wz}CIDhuOEOm1||Kz@w37ZAF@Jv`$MzwG{ zi@0Y-(Vbx<6+Vh`BG88lhh6Vxk+mnK#L&hG{ZqoEw=s^=(=zqpG{2lHa>sTzT_B8s z5;LPp+;+iDB>vuv_}r@b1mJ;LAX!|BK@cS*15x0j&pL4##%k3nd9z>!Tf+;2SwSmf zNnE1;%*>@jL`~sc0g`}XHG=?(_!#91h`o)nmbB#tzjX?dU}5Y?ThP)bp1}&pHx=p+( z0ViDvLXcK~73+l2Ck#?cwf`e9b{WBbP#(Ln3kM1;M&L)^paHhAmrpJ0%s%E%m9-fl zcR7TXwKjlT9_9a~VTEO;MM4WMymO*(&I--sEj^&EGp^4p3ObQNLUV&!oE4D~dSpuQ zsa`341S~SD#B5;VRK%DIC)jmYgceMC?bR{eAleWxan9lyIbnUL+C^CJ1!+4JQup-4%lGc)*a%D zW_MG|4)NWyE7Xmj^Wk$s>YPLThdHwoBSt~x0yqw*?(^s70P2>xPdDHAxdl~;cKML0 zgV6w>Df4b2K%dU*jeddo17g;R+5I+ZuRO%>olgMP&u<@HNe!gw1(>qt!2AqG18ocD z5SRrEMq4AHV`Aj*3ut8K{b!8iH{5?S;k@hqp@BIB5~$jSkn_Sb#VCU`b#jHc9fBIOIza#u#e|1>Se+vGjGDacTr1tw`Gf_<2QbBNvr*0ax8VQ za@<4&jDMa!ecCmEzN^$~`J}}~1p<6akW3Ivw7_uj=G8sc0H%913lkbzzqmu+jRYKv zG5})5yIQOZFq^3XSx%a@Kouo3bZvrKKJ0jew^X*d>Wr??IIAmEQEIMThquUv=E9YLFUTX{vqSSikot7^sl>8QSW7Uxk$ae==%4o^@aP~mr zbf9pGA75HT!*d@R(oFOVU}*~#5sUwUhgwBjECe@U4qkZ3pLLX|prZ(3i^2;wTP|30 zR#+IeY*5^(dh|7BU=iE?e)mM0apbaTWVb$9Ru)?(WI98)Q46pr4GlYk(tm^=vnaKh zl+IW_4QB1P7_Fg5qDnn|FeSI-YqV>hW;yShM= zN@s&3G(mp7dTj8Va$=U8V9o><;9oz=;)X4vd=+d*Oeez3zmx$6>k$yi4lDefHAPKO z(xO_(g;$rwTXHce0T3_GTb0nf5lTRa79-?*`6F%4VEgPx!U`(95xCy{(fc5Y?T;3c z2!4F@id1PGa03~!lX%xD+NaxJyAJcetxZEEpRu+_!WLm@m1rhh289FK7XJ3ybR>Ab zTbmgzlu>Nxap{Psts7<+V5+9s}&A4`bb`Mh+h#ysa z#bT`%5zj~mCwmKDq&pDe=<1MYx*LhvcCPObWu87OS`GjA`bA+U4WhuAMUQn4bJ`u& znSGB5PG9+W!wPViI`jGCx3TB>pbb}%`mNh=Ede>bp???%yr;R0u6;rP`QVAN!Y0H; zN=)Y)_JGY$CrUpgby025#fm4#4nIp55yb&_(|$nU!e&4xEnVyj;)U8l_GhV`91NT< zeQIEiVA&bUN?Y7R|?zfO;^A;yos!mCUnnC zCvD?TZO%?VMz$}2Xco3l+d=w7B$>6^4*t{TV%ILJ_DAy{-SIU8x7@>!etiAeESxNV z|LjA7m#IVMMV@)D?e7_ z&k%h~e1eoNro|M2njNTh+1dsvtn0U?MVmTH8x*9*=54*0y~bbPTELF-KenbNiFt7S z#YBN3QHuPI@%-nyAen#bbJq@#i!K=J)l6~_X2&SnD@2?8_1?#9^8Sfp^wQp-25igd zLouRM?h%M{$GPwMH1-eP?)gGKe*2~lxq>gCQ81DA6wG9i7zjg+l_&6r67uI??ZeYv zILLO@{Q1HQj+*YT%wT-m%Zpo9e^E;@!*+VmQlS5A;0Z1WjI7PY8N=e*+}_oXpp~-i zATV3qN`19=2~qE8q!nlg(0EH=ZlZ%d02V(m02VgjrtMzxN}z?wO@@F$-1sndQF_tF zE1w_1cGrCO{4ADXhj8&VnLz#>F$EZg|HYw7B-6C_dD{Q|m-^vMzM|_D^f=lzfZX-? zUAOpZp9W&sUWIQ-{<15Edc<~1cgm@`UU0>^ZfSNhH&fPiB~mqTaXBGEr}b8SEIvPf zhPY7Azkh9kcLTkXl4%F{tk-Wq!leH7kzsU@XZn&4cq2D^p9F&wkcM4b`6e2g53F$| zaJztc5@+@qeAgQT*)blsyDR&Q_uD-X8n<+Je*CFtY1Ypqpj%WHw9ViX{~q5zM|D#Q zF-O%XGn=F0#R^@YoZl+&T45K2jS(B(sl8<8xc%ov1GXwyYKKC%&Wshex~L%TbV zsI7^Z>`F`){x@*+hR+xoO-4tKxMYWScOgLIxJTTgqcur)VJbHR5bc3f17->B+UlB5 z-dtzIR)@mTni-HTJrV zjP2uF-W!@*_Cf@bM(q|V)l2@6&UD2dA2e$#W|cu*7u0n7r=fa}>_9K%H0_Yr+`R|Q zGS;qkpl19BZCG+6FvdR79a}SWfBwVH>1bMEo$TO+b_5@8 z#Phx%4Pz_#!yk=MD_;n8ieU-Rj_7??MwF)RYo#}Q>Qct6+p>`#Sk^qh?`qcaFinZM zfTyI;4>8ie5_Ftree7qadH;`(@%uhWPQdn#J|1Fn&0yi!wa@vrpS;p?os-Hz|*iYND6TIiA1K56E{^>2v7ZEc-sQ7k9 z_EWV*+;PCqPV%e+w?i~b543mH3t@c5-#9P@xyqgg3lgd#)fcP!4F_}ac?Z+zyb^H* zF4hf53E&ix4lR+UqR-fH)@R2#q3ZXLVN$UX(LLh~8@vws(ET^+uTh zg|rJYgLG1f?2Ai}LY^fMB`)35O}HpIs4p4~HnEhB7K7;Spi@VO?vb5c{ZNCh2#%1M z!ES?<{zZfOR}HpC4Q^vPq2!@MRu2J&o5lwK3|H`&m;SL6L94K(HpAT?+@%b_)Y3rI z0KB`5nX~4&Z}&Tdbw*mdG(eEZB047H%r!U}G@t(CmgsBrj z4P^-ec0CH47m=R>FZuNPD3SpVvLOijI6wAXG?&S8T**6&o1<36hZgh+{T1qhFT(;Dx!0AL0j&$lCeD?Sfr`W$$==+)F?}T?dW7S;8Ul`m{cmZrNRh{ptocz0I^~H6Hxj* z4U?GGK{6~j(eEXWfdzpm`mz!D6aP(qVQxX6SMZB^AydHoPRT6#)+%5pO6ijwlhtN3 z5DPch*luXG_`FJofXu*bYAT^U3)A z?en+r``Y1Y_$~fo1%5yNq8)ynUmoaXIVk9B7+D+xL=bU~dhY+~LF@7!uxscE8%|i2 z^LM`Lh8r*LBNGOMKfK2!dlEE}O_o_TWSF36pOf!HrASNRLm#M<0(aX`ZPaar>q2by z){z0e+MRgE=rR@FJMi_2l4`S}-eq}FW3#M+98AAz)SXpR-%!K<`1+~dkGu-FMuzc~ zcs|CAMZ2hCxlMb5yrUmd!HqE;fg%kwa*S7BqUUcJA?_**_F>_4!jeqN)rs${d7@TvP<3m+^ z%rNcvRNUA7_wjC2$o+Yj-@I{&I6;Mtvuh@@RK_||wZlCAm)q3YJNS%Wnya&R@MXV@ zbITxN{toW>wZCUB#ZHEblZDmClKA9b+X16Bze{cJ?`& zx9v|mJI&%uM#hA-Hx%Pylg=US&~_K|xnvl7JoJ`}y&Y|-Ml=L-Ftpyy%Ci~;t`z@F z^lJF_CQ|U;$5h6zXp<0{;9(B7FZ6d0>(=AYK@t>4O3 zX{6NB)R3-Wh0cs-gV~BuT{IgR5zI&L>lsRjVJQ(+i0}QDsPONUgyVbf+c(=3gAQiA zi*DRDSYvLRd$+17?G!}`4UcDg;$F6CN-9bl@r=iFPpDl2yTs$QYf2`H$3x>2SeEBf z6q8V_2(3Y@zXHW{6s_t7HacZ&C&_tw&MvEP<%SO+vADVlx`SP65{E=XiVtkbT)u(55cDQ zV84X=>FnZdi*;7+yaJuXU&l#zO`bBkV?n{FvH9IPjn2R6rcq-@7Z#4~I<~M=ez&os zyWL#StxK1&-MV!h)3vb6%^fFC8r|{s+eVEZKk4Rj+&fuQ zoak~Ho&h}D<4OA1BD6M#wM(u*u{ny5;z@dFHMa_VmBaEA>rmZ3qB;#iYi*8E^)wN@t19hm6LHPilAXxbfPhw+4zs&Zmq^$)fGgVXCp#3sDN!Nzr zNi1mSzpb)8D`0(4C;lRlixhWlD~Zr>%$kj!R(TZ4M5Xu(o$SCeN|ZDyz%0}yQ@vTH zVR}TlE#4#BNy@}HC2iY{xooU2ZbOEqT!!+A)*umDbz<8`-C2PnzOo*c$U|(QKc?Ug L{WiUrJ)-_Usp)|a diff --git a/lib/wasi-tests/wasitests/hello.wasm b/lib/wasi-tests/wasitests/hello.wasm index 1175a7f7236355c04ce367b09d6fbd750876852c..a2625868b71710512dc06eea44dac9b50b6299a8 100755 GIT binary patch delta 16266 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

N| zYi;K*jxuizYZoUokMX$j`H0R8s}TR7is5+xyJmQ^bKKyb;TPd}oH3%6Z>t2mlLn4x zBX-jrBW`jP&AsFJWkg=isw!UPLAKVsubADX#zS0%%w=Uh^&S~aTC@P;_;eu9iWA3o zbj!$G1b@p$a$0QL$S#Oh|C`L^lu_ZFqe}qGYHIE0uX{Yl)!(zchLw(8^dr4I>MHRy zrCl=EMcUmRH($~ffzjGaa(zED!;Ej~;3b3L1zU~|V#2`D=S)~Nx>@>q-p25v4@nuQ znU3wj4pKO4 z-c@Ry5oIBmY(75X*13OXf~Kf^HG=HIuS{z|gMGnW3W~u!GDm{C7=Uxsz4(}Ns=?hvb)x1a$baQwiE2caLYP~!~ z8m=FVLYzjC(W>zSqr;)F&cd2C zi+WrUvfgCw8XLI_#!WHako8Tn&d~=S0FAe~(G>ZbpHHdAHm<@jLbHwS^yC%!nX5R3 z?#{+6Y>C-CNYRhd=U4QKoR#E4N4Zh|#*6)ibLUkW!Ucyc!}_Xx1BL)M4TozJ$5e#4 zcH&8z+ji)wn2mM$gb$O7y~cnxOGYCpA}7k58nYShVvuft>^13%04w{y8Qm zC5-XdrcX2Fj{n}WkMt{p!@^Kh?qeGo?`#C=#hk_D)rSPhr}{xSpm|uR7vTflDaPER z4@)#VqX-}NGu?G%TBG$GBg4npZKtp-&AKu=fSkFx+Bx6kfQ zv-~n(j*LqahpBp8RujiPXNw&2vM*w-2yW}J3g97beQZK*yLA$I z4fnNx4?6+)C}bh7!2w40aR<&X%cK|jj((WX85}N{m_E{Vtktuae#Q^Os^*~L9&@Zy z3%D!SI?7+yz+07af?-cM>sEaRUmy*_Myp=J6aB^sCX)>+zbWCk0Z&#=%OwtTPX>2c z9$*{oUCuKNx7YZDPEVYWen=kNlI(XJx(B?qE&BqRarJcd^gcRvb?3}A`!SPK@vy82 ziDaDP4{6BnucV&WbQR@v`!x@WHRQjxT2#=J*H$Fgo586zWS20s%XKXo;x*T;Nm=ue z3sDL9;*mLk%*!eF`s)E@{`Gx$*az1S2&|L~LpRY~MXhg;^Dn!hReTk9KwPjL6*W~i zG#8k+p>!@V={D(VcN(;Vr>&VJr|q9~_B2YId@ZoOb@GT{1w#Xp+7LDwVYO1$k$r?C zCg5bW~CM8}qtIm>7*{Q6dZNLCO&L0)RVD z#>QcFFTb8bnunJOb{P{JuT47gH8@QwAz6 zZt7epA!UFT9_wHLPRf#Q##(=zIdjGbXJEz}?xKqEIMGe5`>tW6kUr(}f-I{grUbK& zJCL6N)6pes(a_)=!YHP!U1Xjucc6?^sxm}Adtiadb|5G14$f({l0{OMk|jVJ$D(CC z+onJ=9mj9C1!o_gqA_OnRzSg4=8#M$9h&wy?D*Z&2dJp* znEq&_!7}ym@w>~!+Bs5nE2CbdDv+0wkNL8OyfYt-&Se=!`C*RaB<7mKBQ$40u_dc~ zg(@And3b`&Ddv8dEy0DitP0o$BZwCPY$$%Y<&HE-vdw&=(M!| zcVkm(x6UXl<;bJuvdo|L=rEo>ro3=Nx^(HIQ5+1aa64J?`y)j;V~%IVmgyIBa6D+zf}y+ zvaLY`*Ex=5Fpb6;(DT|?|m@pW5(sl2;8> zm7%ycpdKY<4>BeHez1-e&IY>uq3lGth>Suxl&zpu54CW2w%j1lrUMT(RI{r2Qq7Di zRS;t4Da0y+@9-afDvTCI;o4{cXk^KR^S?%#nla zA&93npuq2im|3zX2f99dOJvP z5XhkymYTolqEdUKL~u3fkb+Zgf?_^--+u##7vZyJH30g8jXa7p{!j zNv6zx*u*Di`D9LGt%JkBarYUr78ez_k&FV>D5vm}UhND_l7u>lB1Xsl25!Jl!$H`1 zntpjAlZywLSw-r;7-+FFEC$Wh>SuqeYZu7T}gIBKR-c1Zb(fb0+900&Pb5claE{mqj zhu~E>ADs~y^XACH2kc10hwlw!RtBQ50qs|Vp&`^~et^z7;uzBOxQ zYt6q_uMz6;wKQkVurAf>WSdQkwQdzd!n0ET+HaQ>JqcXu#4nb>s;?#A7Q_lam0jAT zCiD5Qs-JoZgOS$o7&SC_?IEWQy*6rUI>5`Kw#R87dwboY4wZY&@!7= zKc6Q+FaEQDe1y!B!od$1yhE}>#LG28jatWLa%OYr=EO~zT0?hlS7OT z$lz?eRsAf_QjJ42X%j#4dT`TZn8IH-75FN-2a;>O`DQrR6`Ko_x7sZ>IWP!6t0IPu zZEl9QwqE>2&XJ#02KjvjvV*}GY%!1Ng&#q*9|1#%@e#)2e>PwlnJr_O!C0t(XHrlF zbubRm)g*1PX5{}s96vh(U@sGirChy$6+plYRW$J^NYVeT3SR{DvU%Z6rP8HW&rFD!s^ z9ebJ8&V@fT54Y^#rOj_n9kAg&#g@-1uvR|D>c4^R`JY8%31z-^3pUk)*QVpwTe}m# zdungT@4(lW%J#&<}5#FagP1ZyK?eH>JFj3Sn#GW(SvVeDS7QwnYkeobPYY}DE8I}68K)$ky!AN@vQF_tE8p6&p1)72)^{7Z@ORZXMaSRfw|p7f zZVkBXMjUFnrufhoDYSiC5YI2Z-nL0BsadgoxCU$ejVz$3-jS5y3tZvWt%53)vz0o+{={u{&>eUKS7cA2Z+aL$NO^C)PM4-^Zz*?em#3{F0AgLqggaz zZw4MK-L*GItgm@;Z?e#(wGJ|TgQ^;jiQg=pmFrIY|CrG~Q6cI5La6 zo0l~lYl8g4AKZwu(BOT1H(a)F9Dd*5*AlmQ4xbT84zCiTsz^gWo%Uy<6sPI8Pv4F92Egm}^smn<^Umwi`2}8?ZYWk% zpmgVvpnCWNdg4guu3vq?D#V)uN!{&SF?O)r&PwW9C*`PEdsI1RB#a%D^!d>AN2OcE z_DQOg;aX5W9@MNy==RSak7C$R6^DK?`A_<~q}Z`c-Tz{Hm9e4wjt+sqK0G=$8chuO zYIL-W$fA*}_H~g36@1xVJ@^5Q{j#~bpFgRz?8}zEm5j1+nBM*JQfS+gd()`L(FCb+ z-Mi|$$7qVhNlv|Lv``eqGAnuGaWrXJ+__CP*O2&Azl4_QM5LNR({_xTH8v8zi$Pr8h_$ZQB12& zjKE{B(0*b1j-DQ*2BlAauAD1P*3;hTtWD}0%Q z9cj$T(PAjAKS^E%s@Z{zA2aCMA5*Z(oj>M@n`q^a{cs6;?8gzpOC>*DEXL5hpSp=h zX!}pyYV@D0V^XeaY@;6wcwT^1#R$ep2f#T2)%ns)z@jWhT0KZc|q!~7WZpTIYS?_PXazSq;G zXIiCSkYXrJP#b_R%hm0jLd(u{jCE@_)8R9{^Y&p3&s>UsN%)sPecHsflW&+Xaq6^d z+D^ZDTH70^UfpKe^u?CAWARYoUA#qBN-E&-84Kt(~6MF%uoiWf|ffKgEb z4=^4ptfGSAas&kw*T4@I6c=1^iHZ^d5djqy7gkvLeP4C=BwVh)zkcDvbl3Ijy;rZ^ zRn;{wyB=QST0Kkn|1C}mMNu@5M^L#)Y3O#x3E>sapU0!QHU9H@y~0gf#3;k#<$}lS z)ik%_79!3q+-|Q+Ls``{kDI!w*XgBSR4M+bV#=qdy_;63ZKDC-EFlzA_(%H_g9#0f zh_q`4oe@2~q)(=x@Av{>sX9;aPe3;$CyOG=cGW~h2Od0dx| zd7R6I>ZZL_C5oZsssUZrghkJwVxlY?!YWFJ%I%7&PK}rtQQK+=eO3ve^bD$g^F2j> zfN6FnF(z2wSEkU&F1LeL+lFI{2r1POPFZ!V7v3H@2hcBiG6^U%6L09%5iq`2I0 zc}W%H>NOP88_^H(NW2=6#(2Z9D}^8tNNEii+$~_JW*}l#@E}70pg9aY1UgLJ9%3l| z?iln@dMdr@PEIScJBUkkh+edVs`%>*5tUQ?o2L$`hMMS4l#_zbzj9roKh^F7Hfs85 z+0SLT68%A?d+FlOXMRz$^uS?-OTRw!<##jpKKP&Blp;+>*W3tx^oag34fI6C+m$;# z!$gC(xm(y}mXvH&dIg0a7`pVIsk5(D{lg0|S)tk*qeP+F0*@M+?&~7Hr#F0ky{C8} zB!h1Lpg|xI(EO$dxeP`BCl$osnDwzWd#;)rb_Eqbz?w1K>BacQZGPYmK}GF`wK;CR zOF}mAd!k>ypRV)%FFGB6nfQrX`orQY8syIq`)PtdJnm9(KCd(O*E;Xj{4UoA;*7bs z$#OE*i_7?Nq4JmWI{iAc@^m7U#u7RcxGiZuuOBc3tIdGv(&y9tNizqPb8T4b8T5cr zY1k#X$|H|efq@Dyla7i!#uS@|@vz?wH)L#`Rd2XVz4ByYyr9#8+b@cEHZ2Se6ra(-U@Myh zch8{LaGy_t`+O4I5Iv?TMuMA5=aF!0fg zbSaw!w&*)-+Oi<<|D8@p6Hv`Rh6J|BeXp{n*hn{rlIgAbHwyXYt?+8DsFxWIDcH@c@G$%PXy6YhxlAwRc>#cTEA;7t6H(q#% zQ?7bt$i> zXy&^4vKiQM?_6~0edx%V19829lqo_g_j2*f8dh59HbYfb@up^X(s(LBHMBzY#2&y4 zprq0LDH$1Cn8TKS7lvA>HU`pZP$+s8txCxZxdB}&e|PtTf88?siKkyEOBw_W(Mz{_ z9ZkvX={9!}poXA}LSTq9qE?d)X7ho~!rB-72x$Po$mB92#~;L4y^@AB$cwH#cQsV2 z4B`vbb=<@gujUv19l6L4R+O~q=Pc^i%cu`th=D9#kU8B?=eM6Y7-EGyt;Z_U$`KiA|4`yD|WUHKs{eUod z1}b5F{O0Zo?rE4?`H7w!Ti>?hSa@m0A%(l?Xj)F14MvMOJO=hYmXw~(%8IiZX-2~$OnM+I z->L95Vk{CG4)0|T$9}L)mZZ)V&e)Byns3xVV|w=^;c=EVW`iR z(4>#AqZ-36wfI!|d;5iI{z#}LjP&ILFJ`3Y=VTMwDK+O}mJqFpkY;#typ326)>Bp3 z@GRrS$uOx|(+;(3nI-kQV2w*tnl|^^{P>2}O`OGHVhugrSmp zTNPkgO{~Ln4?_q$DbNkl{N^c7aRoaJu;bF&E~u@r%X z;;>A0orE|up_Af;me@cOniK`kv9GkcNs(AVhnuuW*;)z&^h#^D`xO0Eej~j@Ds63A zkRzGHYAj%DFy6tIW|7(r+KZB#T`%6J;$~e$6|HPGu4~0ChUnP#vY9BEI`#)#rgP2y z#hU1v+@^W|)l4`>f|leCYhjBtv_#CPOOdN%@Yy)RmTan~P+q&l>e-A^s=1Ay&?C3z z6*l@W`(i_0!Jzjnr3C4L3~%ECjQn{z$*MK5oP}y1JXEOTPD+1s1M|deZYb4N}W2)7u!6PAVH z=4nO|M_Bq<3;s{EtNB3jS29|piN90F7H!1`bVrNSXq8m`0vcX)Qe;62zmlg_vn2?- zyGIA{vKa2};(;Qo67S03pg32hn46e#v&dX2IbhRiSq=%;ie^V&%lZZaFe>o%A-d%w_y!VQkgv zq7to1r#0rn+U_1C`t4RtyI+(*0~qrPvn#|>7>G%sbbxFjWZ6*sN2yus7ExY2ARO(_ z)`DNLcD7r>WW@9tJDVW{AyQ?rn*-KJO%dj|zcWaThP$D|2Z5(5Lri`k#55pdxfqJD zmIGG(1Lm4Eg`sGiHOd?I=t~$#*b7y|n4sPZ_n8%s*Ax-lhd)20Tb~bZkH4fdHNHP@rkRVH;Dp zt=`6%5ia5jl-MeTUcSsfCbpTdKj&TKBC)Ku22Wu-V>$JDF z0@i7_U6O{VoKo9{QexBap4HhRsjx@`+73*2_Ff&MWf?Gft!*64 zzdy-uzG4@XP}KeAlXkHlikSG}I-L{z=E+B_vD_N;n@8+o5XFGs+-nsB@kq7VEh%V0 zag$y2hg^3Ce17w#I?Z0cxu8zb<2O$;zky*Y2FLl$AM9cPMfmN9?4l1v7bdlf@hBoy z^qyVhiJ>kwQn#XxVh7zd4^a{4_`hAoj$+3 zbA4;0VkfY|W0rswc~|6*Sjv0atY?<<)A2yCOKO!BI}GYvZ;@8vjhPtLtNn8lppMawGd#{dM||>n_g0z5*q>on zhH;bywn~iS;RQV!_L4Q`Dc+@KWBq-LU>R9jY(>5umd`xQP*^()b1vak-_MhWRI>zT z4SvimJz9g9g*_-KrZ%DdS&bj24p+7wA*V6mPTMNU5EsU*HaQ&CI;u)ScM7?+4NSJ| zM^#r|-0NTm=sZ6fo-MqN%${Qd z%2?<^bs0BF2IQ(s9Zxscst!TrVHxdCEC!J;DE16iNT6J>Lh1?7& z>kzS`Z|jZGEO!VoqlH$%?#7LBm`s3isX|hu(dxb(Xii32rZy3>K##J5S4=|ZwAm2ekS#*^yo3mXVBKiv2e$}lG?N;nMpE~z5#X6ea zuPC~gsdgNuJ*sd=a{vr$rH>E0EQ`zv)zqej-H}in_PfVWLtckT8dzn-8Q$?`8uCrh zXP)t#G&LZWu1Lrun~_d51*?gWC*a|<*FBs^^uQK`yixdFNI$87%3dfZ9j8V@UUv8y zNZ1Q7VaTR}jjf?4zcD(xd=nULU>a0pVH6%|TyFtl959m?473o^xgbww(BehGZ+Ndm zvX19wWROpF86I}-T%4AaNJ~M$QI3hw15T+vM{?RDEe%Xg0KGvMM-2x2#8=_b7OB7; z`;{j4pAy(`$-T>d+8@}vg#+sBU5*`Ndw0TsXA3X7ciAsU{5=nfx?R2OB4-$!*GV3j z_j`Gt1RpyR8k|Evau`q3!GR0lXH2^${C~(LY`Nw}1l`7<9!2jmFAZ0L!YeORkE`cF z7|nchDL)+}XdZu@Yg?H${6y^b)S%Y!RXjF;1F?V5?m?w+d9EAW3}9ytZWOcCe;wQh zhU?_u=AOM0+;++v(h_m?h#?c5?cki4{BuaNoGO_ZeUxnqFFLb2qR-_b7F!k`BV%YN zX(b;ea0nt$i^%GG8a%WqT+Vxk=HqwS(2nAdWh47to10To0a#{3^Y{~ZI`r04%*{N9 znU1}Ff)-zUlQ>MjTzj>Hw6li?4eJED=MHP?`GuLGAES-K27m{i;UNsj8-8_9TRiLm z+==%W0w-%<`}6J7RMtXg*k-~9c$~W#YNo9^0d>>x%rtrOY@a4BW}f)tAqg<0KVY)O zlr$nUdl^?_U!#`a3{7^|bdudyP`?p<#Wq?r;^`Y~wCpspM2k5No&%2nV#_dOOy-$b z@f9dF5;c}Q(JQl)RWz{4;b?Yu6=^tEMZAtP7Y-?kug~>hze8iVC}~(0EoswLfHe>-X+C{AVObqA_b~j)b&?YS}D+rKDYp!dRDF>W2mOcnX3e_yU z!o;UR?Yi=`4h2|CW@)Zk!s`>(WTpfLUz0{rRc|sy-Pw@-gcw<`k9qgpT z+M*d2_Fp_Lw$}M0cPu_`;0wjL@d7lx74w{ z2=b5-yIH_V?H^Qm#pD4bjJXnI*Diz&&hDM8<=tMW$}wOpUYX~Xd{E|?>>dxZkit|r zNL(Z%%}11$1jJH!W)ugNm<52~P){GzwDl?0C#HtOYQV?N$139`i(^#NYU2jPRqLd| z`Hnsw(*Ya~+>$=b@$M^Rx}EVuw{tV``KI!4)JJ3(b%KlU+kf)0&e|-zwN5vF*z}$ z6V25Wyj_m(czg3eH8)_vpj&oSPQ1Obz_>+`*}x=o{H@L~2nG+EJ6;akF#g?*VhOdMn?Zs0q+e?$~$Zv1c$C51p zvC?GD2U0Ob_h^y2oX6m`q@)zPt_sHpOZU>QI~t@(VD>Jt`Y@1^z4Y51Z4=LYj#2U$ zjORK*-R{f^m&jhONkRDQl2}PRhe&2AH-%uurlis0JCoC%VaeiSZ_eoYLaH?Y6K}b* ziw&Fio&`HtoGG56yy6G&`(kl-rtC;@1`6(p9SS9+4A8=TZ4AIk`Q|r#=5J@up7p?3 z7(U&ZRMDTIDH98NonRV}Z01l#zN_5~3FZ_xAh`slqe+$!qFVnhAdC)8Y#rTgtvgUg zc%lsC+_YRUS&w(Ad0>aiEJpHLN|pd^L~I9nv_*krIx+)J4Z<=WqA_OHR=|rT%wdQR z5HwF!SJ9$LeHyLgj)iKCHIy;0D`#|iQg5+~dQ5J1?Rgy`Nlr(gWeKFqfTqcXKti>G zD+t7LRY{AKYewIq4AgS69_veQPkt7Ms5ecy3Y5{yQ=X2VH%%RUyv{T}cmqfwsB;;0 zKELvDNphwL>Jf``F_xj17wSk3Vy@XdLN&rNi&coLXzSF$2^OcA`?;(M8sD`%XekWf zjH+$)>0S4yNs=x0OGaROu}JKq33q4ksIt3@pbo0;z9vaFhp}6waPW2xO=}czxCch= zrGC@GP1i9woSKztCAI@|tsQ8C-$69(>Uvw{YR$l=)b5@(sgS4pdD^|uL3i9UGhv(E zsBz0SI&;s^^9j1?-WME#G>ahpzWW)-WA`!6@7#9_K;_;45Z>3^Uwr=PmJclEzVANJ z4ZS?mA4M;kelv{EFVhD$k_+6IPvwAcNSeXg9Z*eUW{iZ+dwa%!7zwz$TowuKONtUL34=kD8nK%0FBuoP)DkcQ3;`h*Qaf5BxUzQ;IkcEkvtA{m;owRe ze@U+QpLtP~Uzy2VZ}Q;GD;=&|DDz}UgRshlOk4^Xpu){k!zNVqLu?Y$b4 zz|>hW36w@<8||1igBPKHX(8A@t8{Rdr44ZX44#U7H;`x)eh@ZyFa22B2+0y2EO5!}#z85AoEe4xH;>lL9%J*}gUf0xDb*C7Gm%y4!a02t z7D^X@)2L|KMMvl4b+%W;Kn8Do7~9a=83OKswG?(|NwMLEZ*HgqgM3E}vkiQxAYKM& z8Swk()0~GMi)5OTPrma%6JJ5mDLKq+mf2Q9*&5GRP*q)P%wp$To1XM z|HxG_2rz+;+cj=S~(S>$s_hXD`( zhXIm{EFQf;w-h@_zy)Gw4cxS9{+gIaUzES3%cbYD9vr*FGlo3O zpVdrOB6fhD^=B(!8{RnKhQ(z`u|xAkboqjk@Y7tQ_$LSzN6n^g-$iHZjZtZc1r|`v zf>84c?q=52$HZ6#Q6BPZ= zjIs6WpDr}(AYC!L>d$jS7%Bl9gUJ-~fSMO_6H_Md;mgA(dA(F)v4hD#K>Q+w78TLh zCsq}-l-vU4OC?)aNNmPQh)}uUwIm9HMJxZ(laed;iKUe%DmJ<+TQ8j<=+$Q*&pgc2 z!Pof$4@)xf(K65W?2OkQ^2e#(kc z6BTp$OFUsE>r(%_yn+~lQpzh$RCUpJF zO+3e}>dHAUuN3O))zog~pqACE>!4{?tl*M;(<=$AYR{QuEWo#NH6E^fbET>JH&mh* zk|ZvD4S81Wv&+~6`kKlgS2Y#s=YTPn%kBs>(7nT&%fy>Beod~i)gsGla6(FjYS1_G z9K7HN4-G-1LMgOu%@FY|Wvv~VdYJJvE%(7J;g}p7Mn6jP)(*X7TglfA`>(TP0Ul9_ zaBkn7^HD_z@|CNmnL8vKVR7L0A)@5#Y-N_zIX(8!t(C_MEb+v;VXgcgV1YPNJ`w2p zaS|=$&>95n&b(=HJSd?-$2bPb82#d%mpN%x|wUM4r)-q*#Xzgn^LZbE8d%>?B z{(3)k-CA1q`kxwnX>&zhwcp0;W2*X>WULQ~kE#3m31T&^THnI6L9X0uw153n7_{LV z3X@M*H5UEA^*y)n&|fw*isA?Yb{GfS{W8Ni=ip-zWZ2BJViFD$TsVnPLq6X5Dm-<= zH(uUaM<2c`!+qj3+_dQ#bQwMzQiS4h+Xi_He+W0rY?+U@SkD@c1rzv1LIEHVXG=~H3xR84nh`MKSmxcl z0|1;KxE6p1#McPQmB3nz$9V4OMhvHRGolPn-qGh?ZuG(ovXcaZPJlE+f^hf3S2%Iz zbf*A>Sh8KHdjKGu@qPyYrog$N+@`h+OQHBB4n=>R?F%YpVh2|)AX*Cih1zO!`AXOrSJkZQD7re&L7gTfodVYCB)lZUVE8p8~v-R#AhrbBU%u6{Q?{6){7jxpB z^8Gks}kUc?G2$))z{z#o~ClAoXkFURA2p#!20FIpe_zrP| z#_kT|w`})l{C>MTAHT_;o+cjXNH6Yd+wl*qyA&rW!Xnbxjwk#ls9w#7L1%Oji?x=H)s$tQ;|H^c zG|8_+Dji9nr@soR%lFXVzUt6vjXc-korUv~axUoGd9HKLOUzBOm(S|8&FV$1_g{m1 zq%-%YLLQ&o|Lh-<-s=y{{6qbIJJ2!N^8NX1W+?;uo4|`!eceV~wuknA-B?|^hrEYO z&q0!duF+}M!88cQGY3aq(rur&whPr9 z%)Def-1@5>Ue|T&{S`NAiphr#{_5d<#!i?}+`^bvJbA*cp?C#G^M)`BtNphSFU6 z_}d<#6DVb) zshD2*zHO}Z4t?`|b8M&jKRhjl(yAYZKyb9<{Za~jx{`vi{qPicj=YB{z2*2Q-!pd0 z8v5XPG`&T_@l!I9%LDZ~jOkjRyYI7SLz?)J&AoD?jx{Z1eL^ zLqtRB{c}GtmFVZrVlD0bxibTjf0gkkD&iV0s;?_aD9^x?>F@!to7+dXY`KNj|5}u^ z1ugt{3QxxJ6rKIGb1*qshkybnJnK>K!#%o=z#A{;EIgU2`_P%6&UmN(MTi5>(8;K6 z+eUAn&W38-cY0uYR*J5~p*@Ue7*7|Tyy~gc`%LrnTTyC&(tUXHYCEkB>CrQ7QGx_Pq(3*qR#0D0`C-Kg-=RM!%Kcc~u$+xtcaQm2BiYJe4HD&7L zR(BNN+H&#~YV%uO#>iAl7{=krlW(?JVW!g5-!2O;M>Wg(>v*!Pzkw(7tWLLWzje=d zpqxQ-Q#6OutYyu|lL@ZvUfJ&K)uKsxx;5J{z|2LvQyzmdqb>gyEfG29F7z}|Y=-~o z`0tc?lu@UgkN3Lmyj;xMUF$U=#s!k@$<~#tP~H{-`q;VK*54l#ZQS+nR%P@?OBDGUe z!oBG?7T(2oaK_v`j=Mb`#ylQP(_%cD$L+?8rg0X}HJ{h3xw$8X>-djz?!*7=|6JU~ z(E+3E0dkbr%iXer&*$TAjd8b^x!rEBTk`-Ack5ni_PE?`F@ayz+~?&!pO^Y_%;@Gm zw;Lz{0goGa_*^ud?#2+WILU7^P8_S${9(x|mZLIxv_A)EXzr16I&)JvkzwH0m7wmQZAV0@e@(p}0 z|Bn5}zGbWUTE32#^Eddj{5ig!|Bb)NV|P65+951gI{SyX+0}u)DI%_x{trq^O0Q2pjs!v6;m)ojM+X>z(u_C7)9zr{?&de<&|o=<$&BZy5Mahf1jK}Hn3`o2H%4uV zmf$D+sG;UO7-WO`GM3d1XUVQsl{PlW)i7Sfi%e$K>l3e;+zJ)rolUdCnz4X@q6%mh zn%v~sdZ<9pRTaHW-qls07h(FFioqBbaOr>}VY$Er(`AK=gYF*j48S$hZN-f%MqS*v zpvTmTt=o%@#|b(*>ZYeS-~lAJ#d^l;c!Y}sZZqt$;)+d=>K5>t9%~A^nO?w-bNT)D zFpCGgya5}oTm0-5?>GC$F2P!z*ih3sCdLeWceI?GCkQ`E6@jF466O84#b&&K(%O( zHRGt8-;A*bc!{HfsL4kp`!J5?0n|898je$_R%*q@6Sg37i;dOQuS@9_ys)%@+YdtA zV*?)Ig_Hp}uK`kQpLpiyMJ5mN-a$+l;@x{mF$1i{j8zWZy#rqGC4`<{OP^AVu3=9; z2UAVAqKyE6vq9AM1}CViM3wi6*Ol05EM^QBO8_nqsZh|Tm|k!Rw4n-2LyIfu8z9l+ z1LD1M)cwW5cp67-UejmB6o&^um>x@~9GM}SZrRPD5=4^W&)|R zi?p&XF(f1CBV`FlM&^=Uf+apPVQdh827+E-2~pD+<72YYV3LW^KGRQfhxq`EXCN#( z$@C434|9l=lpZYe(IXZb6r;=`=uZ#E*=ps2vYB!C0|H1?K6LY^11i*$UOccm0x#9c ziz)2M)zqGV%d9J{&t>`tlKGfk$#^qN!pA>*#+dYAtUV)XJwy_n5fUU*jY)?>z{1J2 z@J`5+9?N-Q1q69)&_zA&9INP01Aj=bU}o{852RF(5b2-C3@4fi#iW8B(~v3%H)o5d zjz4)#O@W;U+ULPy>myD+&r`tUz%%SlcW68%yUc|M*NsdW=6lV;N0voo5sAucyD8 zCe?+TjNGuxp; zHj_jGoZO4cav592y>%Le7gD9>Hx{Xsd^p_S_j3ZgQ zEUkAu=S9vG48XA-*aR^mC@OUeCTLU;lmM!gm`tu%0gk|Obj!3=7Xby_fZMR?b*QcS z|E7^bnTu)sBND^^JB@MU{zn=wL89qck~rNiF}#J?<@aYfm85)9ryNs)w){ySLdxlr zuaTf2R46k3r}s-YJ|jH}(u!$?Ek?@PJ3YZ~g{iq0#ANDy(*1%lCUWkr*PP@PN25uR zbqLH?Y;01BL0%F%Ayvd>JShemP1(m{n$aSqo~G18F3Xy+MA0-+tTqbSA@Lt0D}0=M zh1JknT#BdhgHr884XBbwL722yj;UD_ku`;2jO+tP6ae;^KY-cbIi-FvT7Xck<^*wA z7o-R9zsI-^!&WhA*n+_@WiWaXX|qC@d>KH-QQ*SJzzwO;@DFkDdcX@bg9C6291qM* z%LVKOo+yYA)i7OaDG;D;#*>mu%ywvos+570$wt=HdnRoVz=Gg4fn(XaLEy;Y+Eo&` z1S^?IJ}nizg5gFfZCq?TEm_puW|1bw)lK8Zdhv1MpjJv}h&Zf@)%uYv87}`2*LTb$ z?R!+Lt()2M7>Ndf+j0V`*i(*hy{B|=(jk|_E&7VBknyoNT{jSxfkqmTqI%aP5`%n& z2sq>;3;2uJ$asJR?!XM{7AJ;l6zwV+@O}XAl2*bwm;MwQb0tgZm4JtMUI5~f?Lj?1 z%zL8%es#w~&nM`lx3pjdp}qa1az>?^4$>=E9t(O+0tNtyF(eE#sFpAQ*%B^C94JMs z=y*yYWR>&c#+~pkH%6LuTt@Bo3PLi)|FZRRMnb(Ea~zk9BP6K_mEz8N^}?r#;e--; zfIswp81E<@WI%4EddJv&evtZr&BkJ4q=Hz@t^NTtBiIS(YVFJB3$SORUIHahNG~CZ)6E;-jQi-M*<7a3QRP zWTkkXOM8KpL>*NY26VYzmc5c$|X*60Qmys%qc&6-7EX`^gxpf|ryGoCFm>8-zGPeHO& z8yAKU!g!@r^zPI&KDFAOikNt9LcLZdWCyParLxLqR)SXe2xBMl1ftQS!G_8FUEyZ~ zZBvAilAO9*b|BB=L?fo=?;txQg&+dyZ{kR$i;azhWS~}GEUA}^!Sz#yz&xGk&t=R~ z@}cm@N1Uw@>?BFjVE7y5)Yy0@_!Gb~iSP4Nm*7va`_Lj{ydXBGBw3rPd&g^CHy%Fu z&e3IOzTd0)Q7T*XpVE)3RvtYrOZ(oP`}e0dKJf6Tnm*)M1bV(JD--R?I;wJ) ztW2;gX={d_>o4dTrz%&3Wo?|@mA3Bax=2>W*p;!W@tRr!{zbXWrWp`NeEN(WJ{Dz{uP9P1MG z+$byE3MQ(IHN@`#i?5*uM%V3cNwty-q8lbhB0z_k>Q$ry( z)9ma*`G-#BBL+^>9D= zyd@rU#L~3RY>POU*2nh>4MfZ$Hl3?4E>HKfC8A&Y&EZ9A-VhH3U3S9d0;~gInojGA zTI)?0c0baP0vay@B^5M2UcGNs@1*_4FG~02dnMIF%cQE(yML=ocZc~578Xa-vr@Jb zn~=A%;A8<5W?~f<8(T!fjIVgfOcC3#13h{)46yBDbi-Ecyja*UKhYUg-T!dIM)jN> zm~Ne_##uB9wr1PJfMACA7n&TE$JD;1ulSBy9?3Bw8E8-p^wFl7pYygTCdA0 zZ1u<^?V*A(#~H15s1Fmtv_9-}end{}ly$_Fjhv1Zl1 zjn&R1lSh!+%}^Tr7`+D}ed1yisxlpsJBT)Kx-ytFTT3&%kiI z*J%mDtq3i@pcjA`tHp*udU(B}M`^u;uKFv|o+31DLy-IVTt{EDzo;)y5(HaEcGq}c zO7H%JSfzAOtVhLd1Cy^%aTa-68fS{mp@IC-Qt?=*^IK0`VOx zR##V`^n_iK6Koc7*?|NbYCIA#nDm6`oZXQ>Tq>q#7uT^dLRwa$b1J(fnkCX+CngT(vG>6rdheY;#nMy92nYl*uLBQN{_YCUkh<%R$f)x*^W$Nib3*cR1f6KJ%9w0jiavBfL zdNIBsHqah0k7PoVhqw`R;}C+@NvWu&J3RlB8T7ydPvKKUxO`b?|z>C$G9Ph4RODT8=jGCOuL0Xlw z#KLjA5%|l+SJZFUj2{!?@^+cNWu#CR3ZvS!O|pX?K#(C1@lvdBmz8AuH@(_KxtQ3d zxxaidmAr{ZH8PIsY#23?2!cPuD*5%xj)XB6?(9_r_Qrh-mUy9q>_IKQ-y;~PM z+crWZbf|4hXTIu9g1-PUe|@nl$Ef=O%^`IKo)NG9rQ(yEc2_)0`lU__50X^{ki`SX zVtZmIDXk26cGP4q#bl&&>7@>LYi_@_cRt2gnbt0P0?DDdgV@(%Q*OP4+UOt1?Ex&) z+BB|>e*ZQNl4@B8X_NQ@TviP9bJ4$j7Dji=YwowJMkB!~&QItpGU_HaP<6Co+AEtR z(2s>%@26+*=yg&AjBBy=k%}%ZjCPLcgq}z}@jrt}8e*_mSyaW+2 zJ^KHpJBStSKjT#;;)!<$)8pj3LFCAO&L5T{S4`z?fhGx!L8U6hWeJT$d4a2Wtwd;b ztnikkySltbyjn0MuI8d4mK2VO+d31%0#v!IP{jr7Oq~v0v1ShLaH)V{UdL9fO6=}v z`cy{1(nO#`4&sa7>z*m@yE7s7Wil53PcG&Wzx7QO3p*{K^{_?fPT@=Q3vJho5W+6H_iUj^~hO`#No@YZE2eioNhFrkUCo< z*ucU~tMHmCaZ6EN!iI+kr4(x!J>e@>73DYj6C3=YsMX+aNvWM^_&X{fAgJYCRILfY z%S;_~TkF+P>u)W4fTnC=;sgo{$U!O@kBiCHKnhjoG*)_k}x^e=QZ!M;$u}{tDPoNA4)*|B>r6@Ox=L=JMVWE@32K)rA z3HTFdJVZ8tu9!3x_?;rrXpo!wH|Jn?Y1cI*f7 zO1G5oI_a{JgSJ>lO%|k)PMtTGJVBZ0PR)P&d$>6gu7NcV|--j)z@pl&eDIf~Cj@b8IALUgQ%z}WAv ziR2!a+YZnr0{~(rR&cPmLKOGNhWlC2V|ZU_H@I~mqe3KJ)mc)I;bsJdjW#r5uJi63 z8(Hs58*OZzRyHa+^t>rywhVhStTT!MVolGSOX@epB(?M#nOf-g`JPR?URo!CxjY^K z5u}rGQJs`=m#vbDRVT#gUM-~DW0dgWI1D~7?}eilH`<&(?a=100}N`Y7ktC;w0Rk#izaV*g;XhPeJ$`aozY{ znUam38+!(#7uRrbicNb09Vg#7qC}RO6Jr<>`z~}sN(b786LAnryn?OKCW6U9GIdX0 z*7oK-;-M-Y;)|2uW*dXyn6Bo7W=vTCc{-m|XcINF*J6U0wK88LBU8E&<7`As>0yvB zC%WL2z%PgLXd)@WZ=A6G5p1;j;2c0~wS1b((^+w-PueiYsz5TgkWj&%d+AEBh4$QZ zC4{z^3#fvYHS!KrF{iphEo)`f6=*)ULiM*-wQKtZ>P4p^+cjt@<5AuZu^i=##rj1p%iq=e8b=8hJTRZ5isY?5@wf)r<3cWqm6+o}jF4^ea-_Jo0 z(@=)YPv}vKucF_i4${!o9;Y$5N|_Xk!hzpKTlvm~ZgK0~^+c}6Bku0sgg;g)R`zeg zW{bD_7h)Yf-#?9F(E%;|Gbw}!=vIAfY1yV^aqED(V%mU=@KQ<&q29n{j6}cnh+RxX z(ePVm=BU=XC<343c9A;Q@mn9(XpQ$<@7Tq7w8r_ZovIiY>$je`^ zV*J*FHJW{X>suRD>h1MghwNesiXOkU&o0KHh`9VsyBLEa?q=<@i?Jx`nAk27DC|ua ztD@hkLpf1ybuJd=SA_WK$Ha~+f?(9gS2St3i+JykA)UvvB@_6+{`bGD4*mFX*=L%_ z9N4nHN?g^7UtXr1mg`jv7VKn_m@}{`dsS2nT;yy5a9}}Oo{H-RAx*VK3?1B#KUi9^ zVDK@XwqZG#Y~@(X=;_aWVhuEUW`BU7g836(3&RGVSy->e|dYT&wHPkBf|J zx?dGd3*jD-okg{rA;)N_13hZExW4BEoG?r(IV%co6`4MqYF1qHntwLwn*TMOxx!*z zuT+uoP)w5Tqv@8Vx!wuK$4T6tOqtVwc$IhP#{CmSZQ^r1-ep)8m#3-E%_z#i$bh zzQM#yzueFzp;jm^E*nz97K+_NS^?h4A(i1ZO$8FCb$OYO))xV2nq*?NcXW;7!)!jsSD-KUMOS}r zEyfgkYDP*?+0w#wqT6}~UAIk0Q%WY| zCd!Tg34ID~p?Hjn`NIY#%i-i4$g#nU37{B0tcmim7J1f7hA?V5P<|E4>vix>huZ;0MuQ(~%>us-jFdB!FueXNeF5H84MEKzki^$4H` ziBJ|uDf9Vk@yh7oj)5USD* zTSU*X7CS6vk1Yt75miofyo*&|=reGERmDQm!0CGcYdTWCyhsQ6Cgtj}7qAd0%Q&6d z=svrTvchl+E=29*-w@_{pp;mq;3@)GuHY!>0v_UQSRoh9o5Z!jZGwlCj$*+;?2GLH zx&XYqo(RcpLfm&rx_@sqFGPMH5y)u({;FR1?E@c}zE1J$RkfD^=0FiB`5 ztuHc1wG{*JxXsS^$*oScB~ai)M(3FN#R2aZcXay0RMw6O*?*83lc_GYOU$|R3SL$! z4&ON|7+n#i65Hlz>u3pi`K_XKV&hEZ1|STa*wfu!d+P=n()E$e;*E(j0yfssHGa;Y+&iU={WyPWGe8YZZFJE(Jz#1GJHTmEGuazr z(bN{+*)nW6wblm)M?GKPRLHLlPe_-k_HqTf1{$@I-&4}*gY+f zcu)XQ+H``Cw2|E+zMa+-p=Ih_&GEO}T^;^%2LH>uLRlMRWZBSKRx?b*m7tR}i`4*T z{<3I4{TB9wSTOwx2W`iePfhR0&nyrv?{4CKmJl^oitFzlz)vg`YwtEOWY67K^srUL z9wJo)cw@V)EZnbd?7=I+1s#(PiCgoflz4jL1N1^*Z@ecx^-Y?>K4*T9-u-m6j4y@e z-Vr{i*gb(}au8A|n2YM6VDH!<$w_O5jFbF3Maz5p z@Y9RLUH3j=Ur9xDcCms}#x4%~bYwE_FQ(fAK|sV32f(~fdL3QkbZUtGH0{9PFCKG|Fb;&G2BFiE^Tqh7?Q?us&2|}UF?*mTrYCbVy84);+3*V1n9VA zFOp1hpgg`b8{vQwsV!)NE|*W)hfJCVoH`=rg|q5~&>yzDmpEVt6eo^|cftX02#y|Y z;@fa?SdNqjfbxxUMgx#RaFOhK;{ny_jLsYA76^Sj=Az3t(h}wVqgJ=mD{6LoPBHEx zU}xy)P611=2@SE0u|tjdjDy*?_OBJ=x{LniyGsLXYcCD4` zXJAK-nyMZd zF#Mm(GP_k0$FWp7NL=Dff=Se4uG=73ry^(*}EtQ{)fi^(V^(yrZqhXr$q^ z8f(Ok2ea5S;*$rPg~`CH)6DW)J(!S_Gew%2N>1Qme`BI(0jW^S-%BymIX-cc0!dgM zX>lGN5GvdR03aHs^fJD-K?zz)#~|`e3wr4+L`pgX7XtLI#P*D0|2W*obXjlU zbcjkYcV0lqTH8h9?6&M1(S3H)fl|B3K9#j9MiHP~x-(0WwY-dg@zRP_FNCS!&?UlD zw|H@OVc3g_YubFxcOow%7=y)=c7`$Vk}|2ybvqMIJ3l)UPU-S!CY-_NlWV2#9cbBb zL$mFT@@Yh%}6Pb5h^Pk4bMr z=84?|_T=(N7RLkXA`Xb5>v+)=x{L0Oh@T$5rooDpP)#dQT_W|nG|LWI-V!4pnanp- zi9?SRW*nxqNS?lvQ3N0&I*h=RUL)5tNy&k@6qhb30>Y+f zS}38SJ4`|%4eP*pjBPIVK)Hbp@v>t82YsQ*=7<@hMV?J2iC4lQdy!M5V2ZBc0$xr- z@LEz*1{=eNRoKFREK*V>DBFXpE(GKFQ4zPGopJ0a1_kM8i)K1}R192@9z0H!mTO|X zj~6Lwqn%DrQ$Q2Dm!yg{3zAd*MJgMVpG4w&+yGYtW{dY1bg^O6x?sc3SeVBCB?=ba zhre4Fc5OI^&0csgQDMFWp9TU6f{hl~E8p<#v@?L= zTUZAZ8d|!jRnNnODScB1V&yw8G9{QQYCz_dX3giazt!+5CJ-Va%6h!ZwGvMD6hT%^l21Sz`Ha0ZT2UZHfkc^8gQNuw(FrqUDtJ+v z9)wN-L942&Qalyuow@R10{GOHBSs&77}Ru zG?7VOI)+M;IR#kLA)iZe4ZY}&u^dEQ%BG!5v1}E>wwG zI>e|9YC%N3sfh_|3ok{=%WI`v^466kIdZW{0TjRZ$C~8&SivPzBu>DHY!AHoc3soj zOmFgRR3GJH1D5~i+51TjL!OhOp8wq74CM~+B|1ou@A9)qKd3r=RGfdV5h_LI`cBDj zm6nimRJV4qm%u^BTjGxObk;U^edBnkk1|8RP``WqFq`dO-1xPH*k;27Ty$Qwp>M*w z1k0p71}K3Y{IVg`$rgx-CJx>6<K31<)*hviyjmk$Z5eg#MH)%5oWlobn8Syt z^znNnBqpf<7dZem7)bx$mj2Bp(`uF@8FC(Zw~JIB z;3HcbJ8CEO63X??){E3G{GwF5-(Hkzm;cgM_LlhSrL{^C%b!UC7}z+jTknw-~)EABT}o?rPLP4Yffa5P-L)U~uIz@vmL&*!v>pl^gmi zOAX^bicLJi^E#UGA#p@r*Q{k$7*)2M~ zJvVK?iY|`RgAk$r>EM)ADUQC~nw5*Xds=rdUxils928U{3rc;BV}z`KIMNj~1lSyr z*xOjqSJ>*e4OEs1N3~^pf+;pn8Da~$OToSmg4HW_y%}cW(^tD?xu6aB8c~vPRL%gN z;s5lpIUT4nD<#awMaTCi@I9Nv`uFqLPonDm z{y5ZVwZGjJd$-V(KPf0Z!TBtN`#`4p2PRCJHpM4?lzKycmRv^$9~~is%Xw zLFPaL<|P%P_5QYX$}4I>zKpJ{2WcqfFff$vDjk0TJ!pHwEi{19Mn%Q?e>|lllQHmL z&-#{Av$gxB`5%78kG~{Nepuu!*(PC%ypIO3t>VOoO~ty8ns^VW+KK}oZD4G%DE;@9 z`IXyiOl}?AM37ooi#Jp44~ke4e|zli8HBQNW(gE;UIja3asSGl=tW;Hfb#7|Eq(d~y{#rL0# zVjIPfBR8e&C#)?MM_DB*u|5{x;J$a{>fdcEtZEpD-i5&+=Z-Z#&8_|zw_^>KW(9?H{Hr1?J*1&WI*QUrRfu z=)$d6in{4wh9Hw#&OdgO@0A@y$nG6t#Ic)ryJ`eDnJH+YF$Fg8B*Yg}_#2x=%zxX5PpB$I0nGR( za@O#cF6lE6SWcv`-LT`tuU5%7Fy4*-;kPj8I|$0I)5(SX%S3K07#*j2 z;Ua_hK_x7dboG!vVv!?yqS<2MiRdi9#=&mK0VSu_E&MDL)C49my*MaWJ&#p7v&=V6 z9phpe7k>Tlxy{mYl>9uRURO_{CCs`$cFnuDBqz!t|WrpeZ zt?;=rrjf~e0vd<`jjpi)t`?2xbdtE3|ADwDZFJ8GaOKq|%;YE)gdD~$hSJRRV+Q`O zIP-?dgX15WF?jD9i;^on=pJi%Clc%X1U>1fRXtU-5GCSdqLSE6-SYA5Mwp0{(l!K5&m% ziQ{v8ze@7(Sob;dh$YU)I`Z(KlPwZtBqn2eDX8#7M2lv*=|vKaw=OYemXfBf5(3PF8&sLa}WM*`DO|J_CM7Ef2W`Nq>JM*5QjSx zLZjSKMEiLV!Q^gK$>=M`hkj;J;B|l8da(IeZ-}*gI-r&c4wp<};h(wD!pL$I^tBKx16PJZyMv+pFG`2bU4QCVzzO#IYM#p-h>8Q;1?%=>LHJ|Z~! z+uiIlar5~Oc#oWaGvG)DevM4g_*p3wTr?CO()xMf{cKFy-=vF%_fDKm3qGhNf2Lcn z?^wjxSlffYy(2Q2u|E9G9g$ZV17?vJ&Iq;0EY9ZgJv$;vI%~q$ZH)|yW2q6)(~zx* z+^MrHet1V@VhT%%Y|z;`wkqR=lh_N^?#MsgYt)(rNg4HMjzwbxa#K);fP)pJ=fu)(6`o zBRy;=$MY=@%ckeI9u}%^YbS`0!MQ@Q)eOGWcp;MGWmDMM$Qmzui*1UG^|3DM(Im3Z z$Cl%LTnszQHf_5-7A@%bjGwLJf8VhUtO#&hZgEk$#TiQ?Wp&t5_QbZ^6WDo{Xp5yz z)CeNe6WOE=e?g0+auOdAA~cra8UoyNk*vDxy?AGMJOqC_@@ri-yY(f*6$%(9`VGyx zK)?LYaQtjry+~yeb9-mY^Rt-9r+$_cIg-T8PV;09-6qBf)u~Uw@ERZJJ111uGBr;1 zT1N%+igZk71EWf(U8Ho8r;^$7zhXj>;q_SQU+Uwf$fzI|LkwNuY(Dy4T zmH#sy2`94j$hRr14ci#WN@YWTH_UqPNax7tRF?j`9T11rcbJdgyNJeNhlr!e!szFU z%&*Vtv9id%`Y@Hs`nZ!(LhoI@d&w+}ry?mS?0T{(*iE%fZAxK{yZC<{p=%c9;r*`+ z&6zZH@|58@ZSvZ-8#Z!y`@G?!+Kw33wy@o>{5E+b+qW$kK59gMZrfpbg>CW*+mC3I z6De(r2_I{~e2FJwH4XpAe}>i@f4_@7(|{GkK7e8pihft*n+B|Bz0Xmm|ER0;ek#&8 zjs2&~GG^diGTqQpG5+C5Y(v&9um{CV6rJh^bvhcWE@wvWXvii+M=gka(U4u& zw8CX*jnPZP6d0gQo-{mX+?ZjLr;NxMdB?QYlP06?xGOTe5$nkEwmsR1?PN`kqc8nu zh9*olM^2hFVUn5c)SdGfnjdZ6$PANpi|OuFm|qw9yU8-yxX72drpC{DBjEs>6f?zV zXesDCKk`d}6-0}7L^=jpyJ+!^$h0790lBOWvZYXj%d*&2%oCZP#roA77Heqr0O2k? ziJv!3*RToa4j%T7d=O&&up~6fW}VofZ9}rzKRtc^SLL)tGkn6NkvXHr zPstfSVT6>=p2&<`V3`})heyNZDTc;@PR-u8O&&gG4EnB%bZo;euS;F%zcY9e)6S$s z9&N)q#w4d2nu&5=WM3QB>)Kf;5^wK8A9^~&ocdKRO>?6j>KkpV#F*N%PZ~LS>bNON zl@6pvCbwl*G)Qh>XdaAB!;|dc9LA9@-yS*CmbGYb6RPW@I0;YEVW;_yNTYVp45v6H zGOQizmUte$Xz&vJOT@qI$g6p*e&n@w?EXlnJT@zGAdh9Ibx&8CIS@~Rz09UQJ1vsZ zp0y2@qrML6pTrZCX{+%hKGo^Tx~*g9hI%1`Me_ z@sy?F3&-855+F=zv9ngr}(Y; zt@w+O=7Z);bFVloJ{612d(HdI+2&?*xp}|&fcdPs$;>*kHt+;y9NA%sK%y*(Kf|>r z$Bho^)&9Lq1_p{v^7%lw$SX6^7_%JHeolTBI3d1?r0Q4!JO`u{qHlj%mM)Z!U-Z>^0dvRJa`bM$Oo7mGL7d%W1`6eb zD^1Ykgf!cT5%k3~shXKF3-~f!6V&-yru9*m6rwmaCQ+-fWr3NLQYK1HA_}p9iKvT5 z95e;u;nCTk6|E!58`NM9?0!payfqQ9CJWPn9$Bb1$5Ja>w#UiRNbOh{f~9~g0_C_D za~$wnHIedYB8*X;Ff@rn-dY=LP3~kmtvSCoK*0C0AS8+^>za65%$h{zId~XkP1I?l zrWNHB@+sF$swAw`$@erDO#vupbV?lNKx2tcq4}4ab}SJkm(V4DGUlH>83?n-Vbmz7 zB3wLdzenlDThWxl3K(iWLh(69#Z=HwKE-MJhcukp-rn7RcVzzhngfTmKwT_=o_7Nba3F37^e zAXzyqfh;JrnpxB%#wt$4BOWz0O&C&|m?*6VidpP=8)Xfs$U+q+mNQNne{{66I*LKL zfGn6~^y>vN?Sl2$^jmVvDq1zMZ|q0 z*^o4xHgI|Sw6S?Lt($6`e7yT+2_5jw(%q^0Hiry>Xhms0rW?M82K^+8Qs9;XSUc_c2VoUv0 zU3P0-%QWo9W8WST!c-E$d?A7Wm?tJXCVdC^UK=-^(*+$U9Q!qplF8c9#c|>OfIl$} zvOpskbxk|~A!VCpH4s_oO;VdtuH?;SzzsM7`w@Bbfc6Q3c%=D+Jt{1b5VvY2`B{>F ziX!ugn&_?ZK#eo^QBV|kG#+e8PcTi7ASXdj6k<~r-~>U?ojJv05t0$?7@Fn?D6JQ8 zG7z)0Vxu!;26otgC#zAkA$e#q|B2cQ)Zk2135akEU|26L(;Gh zXgQp!n6Gu8!6@I17+6o&4h16z+yMP*oW`JTs?X2}uZ zH=dZq+BLGaO=->{vJSnM64I=eOWU*ugMZs5mQYJbI}El!)Z$+_AN!vgh?Fl7&{r}+ z1Gs_doDpHkK8viWFc%9I5g#;Yz8!qWZ@32)MpQRdVg|#oK7&!vwiAH-00K;gH;#niA%tI_6UX zU!oDAm9ju{FNzdVEnq9G2H=8><<MY7?oOkHXisl30*OP<0ruTZL@Pb&hZPZXLVFxc7=d>vj9{G<1iIeB@BqtuZ~&=2~cI((l3NJz&(_Z94= zBvol%ju&#_&L*ZG5@~)NY{{>3bA%Si7>_4P$L{eNX!?uYSUO~-O;uL4yIv`5R}2J= zbayGspGAe{!o^i)r)UNPg=qWK|!P9#Us2fw(2bvcm&4+chJ*$*i=tN}SqeIIV>n{Cw8E&cP%j~Z8edeFd5sOGyl zyT6>dtNndnzGg(CM$H#@t=Y41;etPPVqx!-FW;8B?~%E=@?Y)BhJA1+IKv5&!LSVJLJX13G?qWH|#4uL*)ORgkfPzCSNgzF&M?d zVm~g&AJ?Xfz?9wmHuV>1k z&OknrPE0&5A9lKnujF>8GS~0b1YZzqAM-bQmV3Bq6eTyT3gFn2(k{9v(Qq$DbhGWX zq&J$&*$cORIV;0nrL8NE-p5MYt7KvWkYA|ET(7c~uH2<6bG*uIUHNtk$f&M-F`;Us z9w>GTMEb0%%=9X=bmeMQ=?|Z&E0?RvEDsXfGj^Y^D*Y*ibmeU=ATxC3xA!JECx7^$ zuKkN*NyI}6IT7i8Rq3+?AsH(_Qk6cT*jKS~M~m)CpM?94stjtJfU{HNcT9|LZrLJo z60AxE2N1rnR}+RCWxPMC-yKTs5H%J8;QI#Fd+$%;UA`G}6OHp4FfG$w!$viN`-!Rw zpaB1JkOlh(Wszv-Mj>kdi!R7TxHrfsbqx1NxUVUuvU?uQy_6T8Dz|MG|fa4CX&`#gQ|+ zo*UgtG|=vFt^K7u(Dl;t51Lgdqi6W#_!=%E%feOw8!}T~+bz~Jxram`_%&Qcu9hlu zR}P)4(``(;nboY=+9+S`);aOY9qiM}{*1FWt4(;UaThJA!= z)7vw&RGJ;&!3t{~!~O>wpTmQz7GAhBm8r0mk8-O!-Bd@06@A##bS z$?GmU1Y!hq8c@JnqLmK-k{FO#P7?Pjr8poL_NYjFL%N#;W$H56f?WrjIPwv`*n23J zILPkjO$dnXI5zOyB%4bAnJ9xi0|rebZ1}sL9)S1||!O z#XuP@k{lr4?N@8>B6?~OcsZOpG-DdafU=;EKRDh4@t%6a4s?t=eN_`~qaSg>wOcr_ z@nW$m#QOR2xW0Dl1`eTEuj9XnlqdG>d&(WOFB)FCxtWrSA>RT7S;H!I*+tVJLqUN& zP^Jwi(8|QAV8lJN2z}gAcNd@bOR}Nwc+n_x`{m^MXThAw2`u7`(o&C-II<)ef zk+-dvPxLE_dP+v281jPNT_Wq3u{Y?oAC-%HkL~b##UL^+R;>fBTjCTb>vDS7Epg{k!-TqbfQ6xc+Ai^SXoE-kPW86&Xu~FuEHE z+|6pr;+I{b>{eMS&Hk}o8eODNb%zw2^AXY7j~e8f%1_K4Nm;$^RIx+ut|~*K!yGWN zU?s`Wxj+m~H4&IG(`oS@$E2;ALV@QM?M>y)EX(SFXGTAm1?d5aS`NAoydt{l*oqbl zM!}#Ogaqdf`l*oMtE)?8*Fin7?EY+fPLWHJESxfr!W00|AjCuYS8w#s@FvTDp1g@rjl^4r1%(W!33|+!*}7 z;wH0T@Dk7y7lM80E^uU!!3qWg6~;ZRUS6U}kg%-?3v%OEcCsly4lTWJb@Wuk7s&qH=X}_cgjpR_Tv2NJQ=osZg z`-{$lI&oD}tDah)RLV7Ke@6&dTw83Dkah6V|0b6|=4XyjaLnh!u)QOt3d^a2Uo-91 z>}o{5mYq%>*X|RA$6sN&W~-qJ?K(OCbbN2v$w!mT`2I+z_ z24oLca8Zc|YZ9kYZirOGZ>n@9-Vu3-mOjf}Pu{py?h3`Dmpt~PEAf`Hjh3o4A4?&) z!zRRRNFJ<|mk*sb@_@q76G{rxTi!xRkCCE>oCtj@AsX-fIT;^zqURa)(oVix@Qfxr z;|;?q;6WcAHmOFr3LJbpIKx9DP9caFd2<~M`eunXAG3cd;npk7JRrvnpOCXg1+*pZ zGCrxT!+ZXu%JZnaS(r?fN2mjp&l}OH<|ilUfMS)K2l2-6K}OW|HCM^mQ(P{7M&t{5 z%ZP6JD9v;eW4Iid)s6|-dGQUWp}7zLhVamcVV9)iIcNk}qtAo+R!5ZRjrG%pD?~7? z5?g#AvBkV>IlAJogLyJrs}|SVSRzCB3dckCTU5w+7`~L0pgxQUot`z!gF*x=G1Ed^ zf-@x$0^*RgMvNW=5OQG9fy6LuB=H!N9mGW$6|Q4*6;p>bO`3##8WJ?P1%g%Yy_w@N zWIIPZ5znk~Zg(>4a8#TTi6U16>e{OLmNUiAiBKVsMb~ef5@&`j8E4j@a{idw7jn+X ze&UGSIF5pbP4&3x!UY60&3zP8%zQK^z>W;^0+A>H zl_IJfjXt>x%BMyZ$SoR1h`X>^F%)sXBcDNG0Xk~2kBcLL{mr*V&bw#Zn_8$VdAmv4<<>Ie8Zi{O4>!&Rq-1f+P~X?@Kj z$qkR6w%2U8?S9P6?dfji(_d0?H(?o0P|qlX?|$cuQn6irc}BN(ixp^R_vkU8_biZo z&pi28{-p`*`21~^>vySZ-X(3$@J+sx)SfDB+`OiQt10rWGhZ^lOUij?b!nrm1|A3- zclao}Q2Ewb54KhHu^=~<8DOWt=#R)-&OW_YvxcC9dvsin$k!M=6wsg?Lkb$G;90R8 zy(h&v9V$Ev^p~DAsX&}24!DpuI^~=lVuOsG+Y5WC)6TuIqvuw<+>sI>{0?IP2lti` z9w1A$LmocYLD-mk-jL8*nbrRPNCYR5 z4BLN@zrWyAF<<6gc)TZI_#Lhw4&(xnOuDekSqIe)xwX4f?~uKv0Bf|bWsLnQ%zE6k zToz8R*`~V;L+orG*QAB1mWvI0FT7Her1$llwzqvZs~I_OZj@I}ED|f_oQcP=uzKRu zc3P!Wl*25AW9b_e8PK?%lg71G{pk?sDqyKrYI8ZU#MLPM|09j8)`*aIeknJ7f?am8JAx2tDQ_=Lj;9Lrg9=G_F-l+%4DM9 z=A^v~Cc+eBNNphh>F2;r?k^9w%zKi?1_-`{59WF2Xg$4D(%eze6OQ|(WCh9V@tI|BgCdHz1^B~{3wJ6usSX>}G zL|O`n)rScY0|X_i3e?d`^PoI*`6Su~UR5r-;;jA~$+SvX zooCX-{y}pxA&%tLRbHJMWLKkXUt8E`r%$DeD|@N{WgJio9R!M9Y*cwkmKqhgmi)YS zpnRydeOy5!aP|6eDOH$NJwjM}j@(l_PRy0PC&$I_<>`|Lh&giJI{z(`?mNfTtVppHDz z!aJzAdd=-A#wIODWn*Oq^eISM<>wTpxS{w5%=gqh|2Ba9^%sv0^O~uwx_#J*UCR$(<^Hi`$ln5Y=_Lb zwoV+Bi?8hrv|F!jpNGXkc*Nxv!QHHr@89riQ7?Pl zc#2Q9?^Eh;9AqwABHy^NW9U8-YA=%C+&H$Zp648Jn~YargWTnFSBZZH@E;tA*UO7< z`VqE03VQ)pw|(O!3REsVVieg{UYBZS*(6ecDXqwUX){Q zE-q3z2e=>962P$(xMgpZ$(v)HRVUUm;f=fwa2j>X zkUehcS*XCxYL_~M)wkQ z8O9A;gbZ6P*WOxIqYfzT_t*>R2*ds-VeIXy%%}{B9n=1ol83D!f67x6HHj7(TQnr?<_E-FP*p0JnIGg`)H_bxP4$&V zfC|VjS&$&{QltU5TP?gkChX-%K^A!#@N=XkTo?G26PAn$Ye091jr=S(-%v8PR8|an zW2q%uRZ=ksvAt3DN|xoJD`U6ckrQ4Jv#n8Ho{WX~=@i=Jf@Ir->ZuL`)f?}|@;Ag&+on}|c?`B5eWiFpxBIC3A_VB`Pto_Ya8%PtuE3zLM@jckOBO7DS_t=ySj}H+=;3cPRjAO54g;; z`~dv1wsj{1%tU{mnXZ4lqq?>{-r1#=hfeM`KK*6G^#f_u!4IVWdb=~~C>71W&IhFj z={Rb@T7auyN7U9;U4K%Sst^q}Ypqk4sr*(uCC`~tCLWZx%;}u))6wJ}|L3KpRffdG zG_-Ou1HzmDX3x-7`0+@bZ+=Rei3P}k35F=#Q2@y*DjB)PB}=_gs{O!ND0MH?JMd=# zp4(}(vNX@`xS+t;ypQ~}i$#=+zRjQzK$6pb0NJ#` z6Y{b<1|%|&6hw2A)SFpy3#$fiO5!@(4i^dwP~Tgc7Qd51wjJzLJ{P`UU_oS@A7r*2 zUO>4>rlOGTNXvy}VGEE*Co7PKPbWGE=Et!j1~X$Wi=Ryf^?3pp7$$BY3wjph-n}<2 zGOA7o`38*+lweE4RY{$0Q%{uVzZ3gHN&jm zBa?RxDA~FPKVO@0z`WE!6KyjJl!Yf-=FbqZZZ?(e{Ot{I1YF)zw|3x=vYiOjo&T(Iuoi zB2SAiCQguR;UgV(Tc*lT+p&80y=sq4$m6nAHHL=EN6lJUOwwMHow8MbG(hQ5^Q~;3 zy>~A#LhQtLNOoAwDv_>3~_b)BR`*TYNRK8Bf&<;Zrfj9Vc zZ&LgK^xyb6Dul=eU&|>_+$J)BtaGaSFf|Vj1}3O?v)WN;8aP4ZX(1UjsZxaAlmGki zobFBaN-WokK>wKG82FG81W~H0UU3y=SlxDF)=k^=E0Z7V*jvv)i3mwHzXll&!dawD zTM1sYlEYpm1&;!p=s<_9EIe{_v6G!!SQ zunzwWi_ncbB-Kf4ui^=+k?hc{LApZTaNlXZ4TG8G^awleThmIr4iJqhSo+<|Zz@v6 zXnw1CJNWEZu}jA8FJiyJ_g4}2+WW^1RseCBxYCETKI0qMc+f#Le)hl>P&l}a<}3$G zSM6E!K&l52+d5^w312+x^h(#Bk}uR~?JtlZTfQ z{HB%Fgxk9EPQr~?b)k4(u3a?_`YgX&RZPJbJaQhr;5CnoNt2C>n?Bh)9!awQ>8t0Y z$qsmAf4;iX*4ltz47*9?YExf43i%|U=!(s7YN`t=hchLe_KW&eF&HtL3NU}3 z+hWa6l6}D%#qB?>Y2vm|_7!W}+X|nGJSl3-KDD;fu?&2BZCd5jN&@!HeC!tRbkXBV zY6BiWb+EQ~evRtczJsj1h=6RR<1t}XtD7QFEv%uKIwA#3Pk9RY>f^`v+pMA?qpEmBZB%=DVQ-d~tefbGB82O^o+v(CHx&+c z_!FaYUf?JWw-4YrJjaSB%8&Pi1jlURcQ8D^0qG!4pb_}cTDgO?5q!YP%dr^Fda`?# z|9PPOyd3o8y!4_BMu43kJUJ+>OyMSFa-LFBx$mhasRTV`>azX{@q%2u{tT+*7wgX< zmSIniOk+X5)>p}go>o{&o=H~umgLD6s-)aIkEZd}t!qxx%aPVne68qf=^viC^voY= zDX&lXe1O*Zd`N34zE7lNm3R1&Lh8;Sdj5tnT@=%fQDdU<-9od;1UIV5BsVs(#8=du z-?mUx&DkNp?cgh_nhZ>Q>TiFfs2!iBqRLgzDox$>>_)L!F5L8}Rs^1Asb5LHED z{NHj>&LO!^4%q6HDIkxag!+LCeh1q`TL84(ytPv|mFJ2hHEUwALkP^x3BDHR2jOnv z6x-8ZHXxn$&ejvfHktiGV+BOsTaNJ`7qViUT{RX@0eeqAh z_mjMErf&FK)n>JW^$M=weRgCAv@!fa(#vp%$T`1@%V!&&>fXcqaM4y`;)X?dLQunC zTLEiUe1KZZ@823KFL~)>@%DzHFFzODF!Rk@h5YyHceh(lJwP1Bhl#QIKdTz{fz#7B zdf+tpk8kwovHl^n^1uQ7C^ugrto=WvE;0#O3U+}occ^(9_S>@en|U}eAO2>%z!QT2 z`T8!~E6h_`^26Uv5btg1_u?#(9e~B*(?mt>ALY2W^D_QKL~iQEJW(QVe|s~|*iYPc zn)%U8`EgYoc%R*NS#;tm@yLUu3KZ$o*JZ?6=`R@5hyL5i(AT!Ch9k^`7@2>GE*e1 zTg$LjK>uDiAM2oA`KfG}d&Ua!5?As4J z$vZwQ4sGA0I3XYZaI9IkS$_B7sL-m-s%pdNo%k89gYwA#p4MZ*bE-=7%iaDoO9yl* z7lQ2%R{$Q^D`q93sdsEh{>e2XN45Y8Nz(vCxoy|SUKv(y@7wU~N1a4b3pDOQ1&;L+ z;NS1=BmOFTeOw;jPO3RSW~a3la#(5;Qa%{+ukxmkFGV77&&LzY70<~%e`}ldFsV@a zFZtESCGy6`o?eT1IJF>89OtC(;<(B5kAF1(es{z7jc1ACZ#Xo@1igBuF^IR^EOhJE z%c-9@=KS??;U|CXt_=$EflMMH(1rcFdcsNa-nd|mst(wn%N3u#)NZ2|l==xQeI&zS zly2X=cS3j`8R5>~B0t_c!Aw3QhwK|_&fOyG_KiXm^4`A7@)vV{;DGwzEBOqeO?$B% zvp;6uwM90tFb}iX==192s(9>i3iQ^FREJ zE_H;9gipxHf;+{=7+*Ruzk|K8>NE_F)D_cec^aDlc#y}j*h6dJ&~V6f3Cr5(GW%m2$C{+`pn&{Mc7piHEHe538;`F5 z$C1C#<71*Mg^&ql1@o-UK9N+LLU;iOKfGl`-VBPY1UfJQgQeP~bF-$!gOgDT7V{aJ zM$H`=&nS-bm%tc7C2)m+@}ov)6k{;t0I8H(#E8GSRgJ_l()ygGc}-tMr2|2=u_#8x zLA26}Y;ayBBBM?Q^%=QI!tpCCz#s)nMRT&1dgE895|e>|kU{KnVKBs}KG`Bv5KySe zB8-*@J`~TuZ}zB0{`y=7eg(`cfFNpZ0Cm3s3ctVltt%qH2uKAfB0c@&q!O@2Y%?;E zas#Qn=zu9>=RsUl*o+zREUIRfudo3Cc@6lCZUzR`nmpZ2LhEnfo(alJ=KzeFB{X;< zRp0vueRrT4mY5cckYiv$9KV)_Nst+^f6Xt9t>za|{2~-m5h9kMnZ@t;;sMT-?!sfW z*9^kajlPjdHbpN>wq_~Y~DBY!+eQ=?LU8BP{> zjBw1C7=fv>ewpB84HQgu<3UqCQXSM_WRCbPv|GQCPWOO(>GQ?nTY2Ue*NV4g>@RKP z$6s8Cx9UT0d*#wEFT>lMFYi(1u3qhhe|dX|zhFUk(}d$p!T)9m$~x{W`oIownuPyYJxlb?PWc-=DhpX#|< zxc9%pie;Allv?Py#ZX7`$ro5(;qFk+M@;vhFS6o!6Tc%}fd0XV7BcsfFw#eN_xcXLndjpo(B^Qb! zx%J!iZFc?v_z|$&Jr8?p(&ChW^mNau;opAN_l>7a*jz$nignG?#3V z_x(WH_W$6~cDK1~%aX&Qqd1ak%oio8K0>q;i&A5SC^Oe>*)&~8h#1MR z$qQ14+Y01ORmkoI=Hq={2AT!tk&iC14420^k^3*~IsMuh*G%eJSvm32z5{zt>U+^e z6EB@qRds3qORIYK9eC-aftOSc?APzofdl(r+`p>dC8=`?L@f8dEW^P6@n;(&@b5#Z zy9z{A>&sC*4#nH>Y=h?>E48ga49oixW&W{?|9&LZxlsIh$SPsuK*uoN$1{rOM|cW6 zeJOaY_=af&K;aoC(`qb%8g=NRd~GKQJjcJsFOG^Gn!)?1A%d9YH}ygdwD9=NsJa-Q=fJc$BXYa zm39_?$iNpx`tSd$p0OUHNE}Wb-vf#d?+s#xfjFBD)9wkpUH{X}!e_sbp^vPJPx}B=cuXpVV{8 z6%!{-oqkEr8P`njdF9lLdrY5^x}uM$Xt%gnYvzM^l7www4prvH;?%l6qEEaL^{r6; z3!a#$@im@gUlZKYzM`g!kEUOVZFEBOxp-2qCgRD7H-T@O(pOXpG7MVwU_VjZar<$4 z=re)89JPLVBFdbP`b&M-Pn6Zz?X`$Hqpk@5`DJ!gFz{K!rlZ5eL+1YjqQ4y* diff --git a/lib/wasi-tests/wasitests/path_link.wasm b/lib/wasi-tests/wasitests/path_link.wasm index 306a911e651ae54df22ec5ef6d0a0d4c8d32414d..eae511069d0cb2b3d52cefd440e27a845bd92eb0 100755 GIT binary patch delta 20761 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 Bj0gY# diff --git a/lib/wasi-tests/wasitests/path_rename.wasm b/lib/wasi-tests/wasitests/path_rename.wasm index f76120ab85a8c607c4b6daf112b66eb72fbd2810..7e613b960112f42847a7f805b3629a60a1594655 100755 GIT binary patch delta 23300 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 diff --git a/lib/wasi-tests/wasitests/path_symlink.wasm b/lib/wasi-tests/wasitests/path_symlink.wasm index 61bb0a0224b31c1cbc0c8ddf0a20684c1892f422..c30b16378645f759286a17dea521777a50b3d177 100755 GIT binary patch delta 20963 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 F{|DYS)#3mE diff --git a/lib/wasi-tests/wasitests/quine.wasm b/lib/wasi-tests/wasitests/quine.wasm index 8cf55c4aca28cfa0436c84b395f4d10e862b1dfc..21fb813a378054ab7fb6a980264df6c98ad80a6f 100755 GIT binary patch delta 19943 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 I-Vk&DAIW`HApigX delta 20252 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 diff --git a/lib/wasi-tests/wasitests/readlink.wasm b/lib/wasi-tests/wasitests/readlink.wasm index 26480cf84aaa9e5b016a15791107c1d047f8b411..d8ef0c74fee9b33277b4af5dc0755855585d567b 100755 GIT binary patch delta 19928 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 bA#3YuPh2Kp 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

(path: P, protection: Protect) -> Result where P: AsRef, @@ -54,6 +56,7 @@ impl Memory { } } + /// Create a new memory with the given size and protection. pub fn with_size_protect(size: usize, protection: Protect) -> Result { if size == 0 { return Ok(Self { @@ -89,6 +92,7 @@ impl Memory { } } + /// Create a new memory with the given size. pub fn with_size(size: usize) -> Result { if size == 0 { return Ok(Self { @@ -127,6 +131,7 @@ impl Memory { } } + /// Protect this memory with the given range bounds and protection. pub unsafe fn protect( &mut self, range: impl RangeBounds, @@ -166,6 +171,7 @@ impl Memory { } } + /// Split this memory into multiple memories by the given offset. pub fn split_at(mut self, offset: usize) -> (Memory, Memory) { let page_size = page_size::get(); if offset % page_size == 0 { @@ -187,22 +193,27 @@ impl Memory { } } + /// Gets the size of this memory. pub fn size(&self) -> usize { self.size } + /// Gets a slice for this memory. pub unsafe fn as_slice(&self) -> &[u8] { slice::from_raw_parts(self.ptr, self.size) } + /// Gets a mutable slice for this memory. pub unsafe fn as_slice_mut(&mut self) -> &mut [u8] { slice::from_raw_parts_mut(self.ptr, self.size) } + /// Gets the protect kind of this memory. pub fn protection(&self) -> Protect { self.protection } + /// Gets mutable pointer to the memory. pub fn as_ptr(&self) -> *mut u8 { self.ptr } @@ -238,13 +249,19 @@ impl Clone for Memory { } } +/// Kinds of memory protection. #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)] #[allow(dead_code)] pub enum Protect { + /// No protection. None, + /// Read protection. Read, + /// Read/write protection. ReadWrite, + /// Read/exec protection. ReadExec, + /// Read/write/exec protection. ReadWriteExec, } @@ -259,6 +276,7 @@ impl Protect { } } + /// Returns true if this memory is readable. pub fn is_readable(self) -> bool { match self { Protect::Read | Protect::ReadWrite | Protect::ReadExec | Protect::ReadWriteExec => true, @@ -266,6 +284,7 @@ impl Protect { } } + /// Returns true if this memory is writable. pub fn is_writable(self) -> bool { match self { Protect::ReadWrite | Protect::ReadWriteExec => true, diff --git a/lib/runtime-core/src/table/anyfunc.rs b/lib/runtime-core/src/table/anyfunc.rs index 4a63c8f6249..38cb578f27a 100644 --- a/lib/runtime-core/src/table/anyfunc.rs +++ b/lib/runtime-core/src/table/anyfunc.rs @@ -17,11 +17,13 @@ enum AnyfuncInner<'a> { Managed(DynFunc<'a>), } +/// Anyfunc data type. pub struct Anyfunc<'a> { inner: AnyfuncInner<'a>, } impl<'a> Anyfunc<'a> { + /// Create a new `Anyfunc`. pub unsafe fn new(func: *const vm::Func, signature: Sig) -> Self where Sig: Into>, diff --git a/lib/runtime-core/src/table/mod.rs b/lib/runtime-core/src/table/mod.rs index 8e5c0e03323..997ce5eb1e4 100644 --- a/lib/runtime-core/src/table/mod.rs +++ b/lib/runtime-core/src/table/mod.rs @@ -1,3 +1,5 @@ +//! The runtime table module contains data structures and functions used to create and update wasm +//! tables. use crate::{ error::CreationError, export::Export, @@ -16,16 +18,20 @@ pub use self::anyfunc::Anyfunc; pub(crate) use self::anyfunc::AnyfuncTable; use crate::error::GrowError; +/// Kind of table element. pub enum Element<'a> { + /// Anyfunc. Anyfunc(Anyfunc<'a>), } +/// Kind of table storage. // #[derive(Debug)] pub enum TableStorage { /// This is intended to be a caller-checked Anyfunc. Anyfunc(Box), } +/// Container with a descriptor and a reference to a table storage. pub struct Table { desc: TableDescriptor, storage: Arc>, @@ -128,6 +134,7 @@ impl Table { } } + /// Get a mutable pointer to underlying table storage. pub fn vm_local_table(&mut self) -> *mut vm::LocalTable { let mut storage = self.storage.lock().unwrap(); &mut storage.1 diff --git a/lib/runtime-core/src/trampoline_x64.rs b/lib/runtime-core/src/trampoline_x64.rs index 80de3e0d6bc..3d07484c715 100644 --- a/lib/runtime-core/src/trampoline_x64.rs +++ b/lib/runtime-core/src/trampoline_x64.rs @@ -62,6 +62,7 @@ pub fn get_context() -> *const CallContext { } impl TrampolineBufferBuilder { + /// Creates a new empty `TrampolineBufferBuilder`. pub fn new() -> TrampolineBufferBuilder { TrampolineBufferBuilder { code: vec![], @@ -100,6 +101,7 @@ impl TrampolineBufferBuilder { idx } + /// Adds context RSP state preserving trampoline to the buffer. pub fn add_context_rsp_state_preserving_trampoline( &mut self, target: unsafe extern "C" fn(&mut Ctx, *const CallContext, *const u64), diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 2a38beb1e97..999e29f20c4 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -1,3 +1,5 @@ +//! The typed func module implements a way of representing a wasm function +//! with the correct types from rust. Function calls using a typed func have a low overhead. use crate::{ error::RuntimeError, export::{Context, Export, FuncPointer}, @@ -16,14 +18,22 @@ use std::{ sync::Arc, }; +/// Wasm trap info. #[repr(C)] pub enum WasmTrapInfo { + /// Unreachable trap. Unreachable = 0, + /// Call indirect incorrect signature trap. IncorrectCallIndirectSignature = 1, + /// Memory out of bounds trap. MemoryOutOfBounds = 2, + /// Call indirect out of bounds trap. CallIndirectOOB = 3, + /// Illegal arithmetic trap. IllegalArithmetic = 4, + /// Misaligned atomic access trap. MisalignedAtomicAccess = 5, + /// Unknown trap. Unknown, } @@ -52,12 +62,15 @@ impl fmt::Display for WasmTrapInfo { /// of the `Func` struct. pub trait Kind {} +/// Aliases to an extern "C" type used as a trampoline to a function. pub type Trampoline = unsafe extern "C" fn( vmctx: *mut vm::Ctx, func: NonNull, args: *const u64, rets: *mut u64, ); + +/// Aliases to an extern "C" type used to invoke a function. pub type Invoke = unsafe extern "C" fn( trampoline: Trampoline, vmctx: *mut vm::Ctx, @@ -80,6 +93,7 @@ pub struct Wasm { } impl Wasm { + /// Create new `Wasm` from given parts. pub unsafe fn from_raw_parts( trampoline: Trampoline, invoke: Invoke, @@ -102,8 +116,10 @@ impl Kind for Host {} /// Represents a list of WebAssembly values. pub trait WasmTypeList { + /// CStruct type. type CStruct; + /// Array of return values. type RetArray: AsMut<[u64]>; /// Construct `Self` based on an array of returned values. @@ -175,14 +191,18 @@ where Args: WasmTypeList, Rets: WasmTypeList, { + /// Conver to function pointer. fn to_raw(&self) -> NonNull; } +/// Represents a TrapEarly type. pub trait TrapEarly where Rets: WasmTypeList, { + /// The error type for this trait. type Error: 'static; + /// Get returns or error result. fn report(self) -> Result; } @@ -236,6 +256,7 @@ where } } + /// Get the underlying func pointer. pub fn get_vm_func(&self) -> NonNull { self.f } @@ -246,6 +267,7 @@ where Args: WasmTypeList, Rets: WasmTypeList, { + /// Creates a new `Func`. pub fn new(f: F) -> Func<'a, Args, Rets, Host> where Kind: ExternalFunctionKind, @@ -390,6 +412,7 @@ impl<'a, A: WasmExternType, Rets> Func<'a, (A,), Rets, Wasm> where Rets: WasmTypeList, { + /// Call wasm function and return results. pub fn call(&self, a: A) -> Result { unsafe { ::call(a, self.f, self.inner, self.ctx) } } @@ -397,6 +420,7 @@ where macro_rules! impl_traits { ( [$repr:ident] $struct_name:ident, $( $x:ident ),* ) => { + /// $struct_name for typed funcs. #[repr($repr)] pub struct $struct_name< $( $x ),* > ( $( <$x as WasmExternType>::Native ),* ) where @@ -598,6 +622,7 @@ macro_rules! impl_traits { $( $x: WasmExternType, )* Rets: WasmTypeList, { + /// Call the typed func and return results. #[allow(non_snake_case)] pub fn call(&self, $( $x: $x, )* ) -> Result { #[allow(unused_parens)] diff --git a/lib/runtime-core/src/types.rs b/lib/runtime-core/src/types.rs index bea89ffe39d..feb84383dd1 100644 --- a/lib/runtime-core/src/types.rs +++ b/lib/runtime-core/src/types.rs @@ -1,3 +1,6 @@ +//! The runtime types modules represent type used within the wasm runtime and helper functions to +//! convert to other represenations. + use crate::{memory::MemoryType, module::ModuleInfo, structures::TypedIndex, units::Pages}; use std::borrow::Cow; @@ -41,6 +44,7 @@ pub enum Value { } impl Value { + /// The `Type` of this `Value`. pub fn ty(&self) -> Type { match self { Value::I32(_) => Type::I32, @@ -51,6 +55,7 @@ impl Value { } } + /// Convert this `Value` to a u128 binary representation. pub fn to_u128(&self) -> u128 { match *self { Value::I32(x) => x as u128, @@ -92,12 +97,16 @@ impl From for Value { } } +/// Represents a native wasm type. pub unsafe trait NativeWasmType: Copy + Into where Self: Sized, { + /// Type for this `NativeWasmType`. const TYPE: Type; + /// Convert from u64 bites to self. fn from_binary(bits: u64) -> Self; + /// Convert self to u64 binary representation. fn to_binary(self) -> u64; } @@ -138,12 +147,16 @@ unsafe impl NativeWasmType for f64 { } } +/// A trait to represent a wasm extern type. pub unsafe trait WasmExternType: Copy where Self: Sized, { + /// Native wasm type for this `WasmExternType`. type Native: NativeWasmType; + /// Convert from given `Native` type to self. fn from_native(native: Self::Native) -> Self; + /// Convert self to `Native` type. fn to_native(self) -> Self::Native; } @@ -255,6 +268,7 @@ unsafe impl WasmExternType for f64 { // fn swap(&self, other: Self::Primitive) -> Self::Primitive; // } +/// Trait for a Value type. pub unsafe trait ValueType: Copy where Self: Sized, @@ -274,12 +288,15 @@ macro_rules! convert_value_impl { convert_value_impl!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64); +/// Kinds of element types. #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] pub enum ElementType { /// Any wasm function. Anyfunc, } +/// Describes the properties of a table including the element types, minimum and optional maximum, +/// number of elements in the table. #[derive(Serialize, Deserialize, Debug, Clone, Copy)] pub struct TableDescriptor { /// Type of data stored in this table. @@ -315,14 +332,18 @@ pub enum Initializer { /// Describes the mutability and type of a Global #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] pub struct GlobalDescriptor { + /// Mutable flag. pub mutable: bool, + /// Wasm type. pub ty: Type, } /// A wasm global. #[derive(Serialize, Deserialize, Debug, Clone)] pub struct GlobalInit { + /// Global descriptor. pub desc: GlobalDescriptor, + /// Global initializer. pub init: Initializer, } @@ -340,6 +361,7 @@ pub struct MemoryDescriptor { } impl MemoryDescriptor { + /// Create a new memory descriptor with the given min/max pages and shared flag. pub fn new(minimum: Pages, maximum: Option, shared: bool) -> Result { let memory_type = match (maximum.is_some(), shared) { (true, true) => MemoryType::SharedStatic, @@ -357,6 +379,7 @@ impl MemoryDescriptor { }) } + /// Returns the `MemoryType` for this descriptor. pub fn memory_type(&self) -> MemoryType { self.memory_type } @@ -380,6 +403,7 @@ pub struct FuncSig { } impl FuncSig { + /// Creates a new function signatures with the given parameter and return types. pub fn new(params: Params, returns: Returns) -> Self where Params: Into>, @@ -391,14 +415,17 @@ impl FuncSig { } } + /// Parameter types. pub fn params(&self) -> &[Type] { &self.params } + /// Return types. pub fn returns(&self) -> &[Type] { &self.returns } + /// Returns true if parameter types match the function signature. pub fn check_param_value_types(&self, params: &[Value]) -> bool { self.params.len() == params.len() && self @@ -427,14 +454,18 @@ impl std::fmt::Display for FuncSig { } } +/// Trait that represents Local or Import. pub trait LocalImport { + /// Local type. type Local: TypedIndex; + /// Import type. type Import: TypedIndex; } #[rustfmt::skip] macro_rules! define_map_index { ($ty:ident) => { + /// Typed Index for $ty #[derive(Serialize, Deserialize)] #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct $ty (u32); @@ -475,6 +506,7 @@ define_map_index![ macro_rules! define_local_or_import { ($ty:ident, $local_ty:ident, $imported_ty:ident, $imports:ident) => { impl $ty { + /// Converts self into `LocalOrImport`. pub fn local_or_import(self, info: &ModuleInfo) -> LocalOrImport<$ty> { if self.index() < info.$imports.len() { LocalOrImport::Import(::Import::new(self.index())) @@ -485,12 +517,14 @@ macro_rules! define_local_or_import { } impl $local_ty { + /// Convert up. pub fn convert_up(self, info: &ModuleInfo) -> $ty { $ty ((self.index() + info.$imports.len()) as u32) } } impl $imported_ty { + /// Convert up. pub fn convert_up(self, _info: &ModuleInfo) -> $ty { $ty (self.index() as u32) } @@ -511,6 +545,7 @@ define_local_or_import![ (GlobalIndex | (LocalGlobalIndex, ImportedGlobalIndex): imported_globals), ]; +/// Index for signature. #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct SigIndex(u32); impl TypedIndex for SigIndex { @@ -525,11 +560,14 @@ impl TypedIndex for SigIndex { } } +/// Kind of local or import type. pub enum LocalOrImport where T: LocalImport, { + /// Local. Local(T::Local), + /// Import. Import(T::Import), } @@ -537,6 +575,7 @@ impl LocalOrImport where T: LocalImport, { + /// Returns `Some` if self is local, `None` if self is an import. pub fn local(self) -> Option { match self { LocalOrImport::Local(local) => Some(local), @@ -544,6 +583,7 @@ where } } + /// Returns `Some` if self is an import, `None` if self is local. pub fn import(self) -> Option { match self { LocalOrImport::Import(import) => Some(import), diff --git a/lib/runtime-core/src/units.rs b/lib/runtime-core/src/units.rs index e8232efc8aa..2e8f2c0a595 100644 --- a/lib/runtime-core/src/units.rs +++ b/lib/runtime-core/src/units.rs @@ -1,12 +1,17 @@ +//! The units module provides common WebAssembly units like `Pages` and conversion functions into +//! other units. use crate::error::PageError; use std::{ fmt, ops::{Add, Sub}, }; +/// The page size in bytes of a wasm page. pub const WASM_PAGE_SIZE: usize = 65_536; +/// Tbe max number of wasm pages allowed. pub const WASM_MAX_PAGES: usize = 65_536; // From emscripten resize_heap implementation +/// The minimum number of wasm pages allowed. pub const WASM_MIN_PAGES: usize = 256; /// Units of WebAssembly pages (as specified to be 65,536 bytes). @@ -14,6 +19,7 @@ pub const WASM_MIN_PAGES: usize = 256; pub struct Pages(pub u32); impl Pages { + /// Checked add of Pages to Pages. pub fn checked_add(self, rhs: Pages) -> Result { let added = (self.0 as usize) + (rhs.0 as usize); if added <= WASM_MAX_PAGES { @@ -27,6 +33,7 @@ impl Pages { } } + /// Calculate number of bytes from pages. pub fn bytes(self) -> Bytes { self.into() } diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index 2bb734a04d8..bf15d136b31 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -1,3 +1,5 @@ +//! The runtime vm module contains data structures and helper functions used during runtime to +//! execute wasm instance functions. pub use crate::backing::{ImportBacking, LocalBacking, INTERNALS_SIZE}; use crate::{ error::CallResult, @@ -36,6 +38,7 @@ use std::collections::HashMap; #[repr(C)] pub struct Ctx { // `internal` must be the first field of `Ctx`. + /// InternalCtx data field pub internal: InternalCtx, pub(crate) local_functions: *const *const Func, @@ -43,7 +46,9 @@ pub struct Ctx { /// These are pointers to things that are known to be owned /// by the owning `Instance`. pub local_backing: *mut LocalBacking, + /// Mutable pointer to import data pub import_backing: *mut ImportBacking, + /// Const pointer to module inner data pub module: *const ModuleInner, /// This is intended to be user-supplied, per-instance @@ -110,22 +115,31 @@ pub struct InternalCtx { /// modules safely. pub dynamic_sigindices: *const SigId, + /// Const pointer to Intrinsics. pub intrinsics: *const Intrinsics, + /// Stack lower bound. pub stack_lower_bound: *mut u8, + /// Mutable pointer to memory base. pub memory_base: *mut u8, + /// Memory bound. pub memory_bound: usize, + /// Mutable pointer to internal fields. pub internals: *mut [u64; INTERNALS_SIZE], // TODO: Make this dynamic? + /// Interrupt signal mem. pub interrupt_signal_mem: *mut u8, } static INTERNAL_FIELDS: AtomicUsize = AtomicUsize::new(0); +/// An internal field. pub struct InternalField { + /// Init once field. init: Once, + /// Inner field. inner: UnsafeCell, } @@ -133,6 +147,7 @@ unsafe impl Send for InternalField {} unsafe impl Sync for InternalField {} impl InternalField { + /// Allocate and return an `InternalField`. pub const fn allocate() -> InternalField { InternalField { init: Once::new(), @@ -140,6 +155,7 @@ impl InternalField { } } + /// Get the index of this `InternalField`. pub fn index(&self) -> usize { let inner: *mut usize = self.inner.get(); self.init.call_once(|| { @@ -157,9 +173,12 @@ impl InternalField { } } +/// A container for VM instrinsic functions #[repr(C)] pub struct Intrinsics { + /// Const pointer to memory grow `Func`. pub memory_grow: *const Func, + /// Const pointer to memory size `Func`. pub memory_size: *const Func, /*pub memory_grow: unsafe extern "C" fn( ctx: &mut Ctx, @@ -176,27 +195,33 @@ unsafe impl Send for Intrinsics {} unsafe impl Sync for Intrinsics {} impl Intrinsics { + /// Memory grow offset #[allow(clippy::erasing_op)] pub fn offset_memory_grow() -> u8 { (0 * ::std::mem::size_of::()) as u8 } + /// Memory size offset pub fn offset_memory_size() -> u8 { (1 * ::std::mem::size_of::()) as u8 } } +/// Local static memory intrinsics pub static INTRINSICS_LOCAL_STATIC_MEMORY: Intrinsics = Intrinsics { memory_grow: vmcalls::local_static_memory_grow as _, memory_size: vmcalls::local_static_memory_size as _, }; +/// Local dynamic memory intrinsics pub static INTRINSICS_LOCAL_DYNAMIC_MEMORY: Intrinsics = Intrinsics { memory_grow: vmcalls::local_dynamic_memory_grow as _, memory_size: vmcalls::local_dynamic_memory_size as _, }; +/// Imported static memory intrinsics pub static INTRINSICS_IMPORTED_STATIC_MEMORY: Intrinsics = Intrinsics { memory_grow: vmcalls::imported_static_memory_grow as _, memory_size: vmcalls::imported_static_memory_size as _, }; +/// Imported dynamic memory intrinsics pub static INTRINSICS_IMPORTED_DYNAMIC_MEMORY: Intrinsics = Intrinsics { memory_grow: vmcalls::imported_dynamic_memory_grow as _, memory_size: vmcalls::imported_dynamic_memory_size as _, @@ -509,7 +534,9 @@ pub struct Func(InnerFunc); #[derive(Debug, Clone)] #[repr(C)] pub struct ImportedFunc { + /// Const pointer to `Func`. pub func: *const Func, + /// Mutable pointer to `Ctx`. pub vmctx: *mut Ctx, } @@ -517,15 +544,18 @@ pub struct ImportedFunc { unsafe impl Send for ImportedFunc {} impl ImportedFunc { + /// Offset to func. #[allow(clippy::erasing_op)] // TODO pub fn offset_func() -> u8 { 0 * (mem::size_of::() as u8) } + /// Offset to vmctx. pub fn offset_vmctx() -> u8 { 1 * (mem::size_of::() as u8) } + /// Size of an `ImportedFunc`. pub fn size() -> u8 { mem::size_of::() as u8 } @@ -547,15 +577,18 @@ pub struct LocalTable { unsafe impl Send for LocalTable {} impl LocalTable { + /// Offset base. #[allow(clippy::erasing_op)] // TODO pub fn offset_base() -> u8 { 0 * (mem::size_of::() as u8) } + /// Offset count. pub fn offset_count() -> u8 { 1 * (mem::size_of::() as u8) } + /// Size of a `LocalTable`. pub fn size() -> u8 { mem::size_of::() as u8 } @@ -579,15 +612,18 @@ pub struct LocalMemory { unsafe impl Send for LocalMemory {} impl LocalMemory { + /// Offset base. #[allow(clippy::erasing_op)] // TODO pub fn offset_base() -> u8 { 0 * (mem::size_of::() as u8) } + /// Offset bound. pub fn offset_bound() -> u8 { 1 * (mem::size_of::() as u8) } + /// Size of a `LocalMemory`. pub fn size() -> u8 { mem::size_of::() as u8 } @@ -597,24 +633,29 @@ impl LocalMemory { #[derive(Debug, Clone, Copy)] #[repr(C)] pub struct LocalGlobal { + /// Data. pub data: u128, } impl LocalGlobal { + /// Offset data. #[allow(clippy::erasing_op)] // TODO pub fn offset_data() -> u8 { 0 * (mem::size_of::() as u8) } + /// A null `LocalGlobal`. pub fn null() -> Self { Self { data: 0 } } + /// Size of a `LocalGlobal`. pub fn size() -> u8 { mem::size_of::() as u8 } } +/// Identifier for a function signature. #[derive(Debug, Clone, Copy)] #[repr(transparent)] pub struct SigId(pub u32); @@ -623,8 +664,11 @@ pub struct SigId(pub u32); #[derive(Debug, Clone, Copy)] #[repr(C)] pub struct Anyfunc { + /// Const pointer to `Func`. pub func: *const Func, + /// Mutable pointer to `Ctx`. pub ctx: *mut Ctx, + /// Sig id of this function pub sig_id: SigId, } @@ -632,6 +676,7 @@ pub struct Anyfunc { unsafe impl Send for Anyfunc {} impl Anyfunc { + /// A null `Anyfunc` value. pub fn null() -> Self { Self { func: ptr::null(), @@ -640,19 +685,23 @@ impl Anyfunc { } } + /// The offset for this func. #[allow(clippy::erasing_op)] // TODO pub fn offset_func() -> u8 { 0 * (mem::size_of::() as u8) } + /// The offset of the vmctx. pub fn offset_vmctx() -> u8 { 1 * (mem::size_of::() as u8) } + /// The offset of the sig id. pub fn offset_sig_id() -> u8 { 2 * (mem::size_of::() as u8) } + /// The size of `Anyfunc`. pub fn size() -> u8 { mem::size_of::() as u8 } From ff4c1572858676a9fabbd827e5b5d13bd116849d Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 10 Nov 2019 13:15:32 -0600 Subject: [PATCH 094/342] Add runtime core deny missing docs description to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0da24a7afc..d71b7046ec3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## **[Unreleased]** +- [#942](https://github.com/wasmerio/wasmer/pull/942) Deny missing docs in runtime core and add missing docs - [#936](https://github.com/wasmerio/wasmer/pull/939) Fix bug causing attempts to append to files with WASI to delete the contents of the file - [#940](https://github.com/wasmerio/wasmer/pull/940) Update supported Rust version to 1.38+ - [#921](https://github.com/wasmerio/wasmer/pull/921) In LLVM backend, annotate all memory accesses with TBAA metadata. From 328ab0a93b59f0c0ec47489b2a65d1faa39abac6 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 10 Nov 2019 13:43:39 -0600 Subject: [PATCH 095/342] Remove macro identifiers which don't work in rustdoc comments --- lib/runtime-core/src/typed_func.rs | 2 +- lib/runtime-core/src/types.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 999e29f20c4..7904cb0b6d0 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -420,7 +420,7 @@ where macro_rules! impl_traits { ( [$repr:ident] $struct_name:ident, $( $x:ident ),* ) => { - /// $struct_name for typed funcs. + /// Struct for typed funcs. #[repr($repr)] pub struct $struct_name< $( $x ),* > ( $( <$x as WasmExternType>::Native ),* ) where diff --git a/lib/runtime-core/src/types.rs b/lib/runtime-core/src/types.rs index feb84383dd1..1b19bbc3d91 100644 --- a/lib/runtime-core/src/types.rs +++ b/lib/runtime-core/src/types.rs @@ -465,7 +465,7 @@ pub trait LocalImport { #[rustfmt::skip] macro_rules! define_map_index { ($ty:ident) => { - /// Typed Index for $ty + /// Typed Index #[derive(Serialize, Deserialize)] #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct $ty (u32); From 07ca48a34fed13b7cb0f5ead0673c7d5ccc45a27 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 10 Nov 2019 14:26:11 -0600 Subject: [PATCH 096/342] Try initial travis arm64 setup --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000000..702c28c1feb --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +arch: + - arm64 + +language: rust +rust: + - nightly + +script: + - make spectests-singlepass \ No newline at end of file From 1f9316b5ae009699deb6becc8c8c05fd2ccea7ff Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 10 Nov 2019 14:31:36 -0600 Subject: [PATCH 097/342] Update Protect enum with suggestions --- lib/runtime-core/src/sys/unix/memory.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/runtime-core/src/sys/unix/memory.rs b/lib/runtime-core/src/sys/unix/memory.rs index e0c2a6705cb..051dc1f0ebf 100644 --- a/lib/runtime-core/src/sys/unix/memory.rs +++ b/lib/runtime-core/src/sys/unix/memory.rs @@ -253,15 +253,15 @@ impl Clone for Memory { #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)] #[allow(dead_code)] pub enum Protect { - /// No protection. + /// Read/write/exec allowed. None, - /// Read protection. + /// Read only. Read, - /// Read/write protection. + /// Read/write only. ReadWrite, - /// Read/exec protection. + /// Read/exec only. ReadExec, - /// Read/write/exec protection. + /// Read/write/exec only. ReadWriteExec, } From 2d00b2589ef23aebf07c792fe604f66f5812dd49 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 10 Nov 2019 14:37:36 -0600 Subject: [PATCH 098/342] Update with PR review suggestions --- lib/runtime-core/src/error.rs | 6 ++++++ lib/runtime-core/src/vm.rs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/runtime-core/src/error.rs b/lib/runtime-core/src/error.rs index 2847d56ead0..f2fcf7ebd32 100644 --- a/lib/runtime-core/src/error.rs +++ b/lib/runtime-core/src/error.rs @@ -6,16 +6,22 @@ use std::any::Any; /// Aliases the standard `Result` type as `Result` within this module. pub type Result = std::result::Result; +/// Result of an attempt to compile the provided WebAssembly module into a `Module`. /// Aliases the standard `Result` with `CompileError` as the default error type. pub type CompileResult = std::result::Result; +/// Result of an attempt to link the provided WebAssembly instance. /// Aliases the standard `Result` with `Vec` as the default error type. pub type LinkResult = std::result::Result>; +/// Result of an attempt to run the provided WebAssembly instance. /// Aliases the standard `Result` with `RuntimeError` as the default error type. pub type RuntimeResult = std::result::Result; +/// Result of an attempt to call the provided WebAssembly instance. /// Aliases the standard `Result` with `CallError` as the default error type. pub type CallResult = std::result::Result; +/// Result of an attempt to resolve a WebAssembly function by name. /// Aliases the standard `Result` with `ResolveError` as the default error type. pub type ResolveResult = std::result::Result; +/// Result of an attempt to parse bytes into a WebAssembly module. /// Aliases the standard `Result` with `ParseError` as the default error type. pub type ParseResult = std::result::Result; diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index bf15d136b31..0584633dac8 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -577,7 +577,7 @@ pub struct LocalTable { unsafe impl Send for LocalTable {} impl LocalTable { - /// Offset base. + /// Offset to base. #[allow(clippy::erasing_op)] // TODO pub fn offset_base() -> u8 { 0 * (mem::size_of::() as u8) From 41d207d296aa21f0efd672f63ceac2e79757f455 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 10 Nov 2019 14:43:23 -0600 Subject: [PATCH 099/342] Trigger a build From 2f699a369b972fa79e9836769b1313ffa61f84cf Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 10 Nov 2019 14:51:06 -0600 Subject: [PATCH 100/342] Add cmake to CI --- .travis.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 702c28c1feb..613144010cc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,4 +6,9 @@ rust: - nightly script: - - make spectests-singlepass \ No newline at end of file + - make spectests-singlepass + +addons: + apt: + packages: + - cmake \ No newline at end of file From 9828a3719642762f9d87d5a24abcb2ec6539c9e1 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 10 Nov 2019 14:58:55 -0600 Subject: [PATCH 101/342] Whitelist specific branches to run --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 613144010cc..4690731fd6f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,4 +11,8 @@ script: addons: apt: packages: - - cmake \ No newline at end of file + - cmake + +branches: + only: + - feature/singlepass-aarch64 \ No newline at end of file From 82ec5e970af7a1e492bdfb30333949c10d2efd48 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 10 Nov 2019 15:16:07 -0600 Subject: [PATCH 102/342] Add additional rustdocs for missing docs found during CI --- lib/runtime-core/src/fault.rs | 1 + lib/runtime-core/src/tiering.rs | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index 85a239783e1..a2dd8f5e1fb 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -377,6 +377,7 @@ pub struct FaultInfo { pub known_registers: [Option; 32], } +/// Gets fault info for the given siginfo and context pointers. #[cfg(all(target_os = "linux", target_arch = "x86_64"))] pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> FaultInfo { use libc::{ diff --git a/lib/runtime-core/src/tiering.rs b/lib/runtime-core/src/tiering.rs index 21a9ea2d377..bb4426b125d 100644 --- a/lib/runtime-core/src/tiering.rs +++ b/lib/runtime-core/src/tiering.rs @@ -1,3 +1,5 @@ +//! The tiering module supports switching between code compiled with different optimization levels +//! as runtime. use crate::backend::{Compiler, CompilerConfig}; use crate::compile_with_config; use crate::fault::{ @@ -22,12 +24,17 @@ impl Drop for Defer { } } +/// Kind of shell exit operation. pub enum ShellExitOperation { + /// Operation to continue with an instance image. ContinueWith(InstanceImage), } +/// Context for an interactive shell. pub struct InteractiveShellContext { + /// Optional instance image. pub image: Option, + /// Flag to indicate patching. pub patched: bool, } @@ -70,6 +77,7 @@ unsafe fn do_optimize( } } +/// Runs an instance with tiering. pub unsafe fn run_tiering ShellExitOperation>( module_info: &ModuleInfo, wasm_binary: &[u8], From ea3b6fa6d791f2a4af285329de95d04b2ba1b414 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 10 Nov 2019 16:03:43 -0600 Subject: [PATCH 103/342] Add missing rustdocs for Windows code --- lib/runtime-core/src/loader.rs | 3 +++ lib/runtime-core/src/sys/windows/memory.rs | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/lib/runtime-core/src/loader.rs b/lib/runtime-core/src/loader.rs index d494863acd1..84d2bbbfb83 100644 --- a/lib/runtime-core/src/loader.rs +++ b/lib/runtime-core/src/loader.rs @@ -133,14 +133,17 @@ unsafe impl Sync for CodeMemory {} #[cfg(not(unix))] impl CodeMemory { + /// Creates a new code memory with the given size. pub fn new(_size: usize) -> CodeMemory { unimplemented!("CodeMemory::new"); } + /// Makes this code memory executable. pub fn make_executable(&self) { unimplemented!("CodeMemory::make_executable"); } + /// Makes this code memory writable. pub fn make_writable(&self) { unimplemented!("CodeMemory::make_writable"); } diff --git a/lib/runtime-core/src/sys/windows/memory.rs b/lib/runtime-core/src/sys/windows/memory.rs index 888aeff4dfb..411dee5b779 100644 --- a/lib/runtime-core/src/sys/windows/memory.rs +++ b/lib/runtime-core/src/sys/windows/memory.rs @@ -12,6 +12,7 @@ use winapi::um::winnt::{ unsafe impl Send for Memory {} unsafe impl Sync for Memory {} +/// Data for a sized and protected region of memory. #[derive(Debug)] pub struct Memory { ptr: *mut u8, @@ -20,6 +21,7 @@ pub struct Memory { } impl Memory { + /// Create a new memory from the given path value and protection. pub fn with_size_protect(size: usize, protection: Protect) -> Result { if size == 0 { return Ok(Self { @@ -52,6 +54,7 @@ impl Memory { } } + /// Create a new memory with the given size. pub fn with_size(size: usize) -> Result { if size == 0 { return Ok(Self { @@ -79,6 +82,7 @@ impl Memory { } } + /// Protect this memory with the given range bounds and protection. pub unsafe fn protect( &mut self, range: impl RangeBounds, @@ -120,6 +124,7 @@ impl Memory { } } + /// Split this memory into multiple memories by the given offset. pub fn split_at(mut self, offset: usize) -> (Memory, Memory) { let page_size = page_size::get(); if offset % page_size == 0 { @@ -140,22 +145,27 @@ impl Memory { } } + /// Gets the size of this memory. pub fn size(&self) -> usize { self.size } + /// Gets a slice for this memory. pub unsafe fn as_slice(&self) -> &[u8] { slice::from_raw_parts(self.ptr, self.size) } + /// Gets a mutable slice for this memory. pub unsafe fn as_slice_mut(&mut self) -> &mut [u8] { slice::from_raw_parts_mut(self.ptr, self.size) } + /// Gets the protect kind of this memory. pub fn protection(&self) -> Protect { self.protection } + /// Gets mutable pointer to the memory. pub fn as_ptr(&self) -> *mut u8 { self.ptr } @@ -192,12 +202,17 @@ impl Clone for Memory { } } +/// Kinds of memory protection. #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)] #[allow(dead_code)] pub enum Protect { + /// Read/write/exec allowed. None, + /// Read only. Read, + /// Read/write only. ReadWrite, + /// Read/exec only. ReadExec, } @@ -211,6 +226,7 @@ impl Protect { } } + /// Returns true if this memory is readable. pub fn is_readable(self) -> bool { match self { Protect::Read | Protect::ReadWrite | Protect::ReadExec => true, @@ -218,6 +234,7 @@ impl Protect { } } + /// Returns true if this memory is writable. pub fn is_writable(self) -> bool { match self { Protect::ReadWrite => true, From a74acb7a8a7a18dd9eabd1c735ea97c488db0b3c Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 10 Nov 2019 16:28:33 -0600 Subject: [PATCH 104/342] Add missing rustdoc for macro debug --- lib/runtime-core/src/macros.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/runtime-core/src/macros.rs b/lib/runtime-core/src/macros.rs index c4e05f97859..a9dc6721cae 100644 --- a/lib/runtime-core/src/macros.rs +++ b/lib/runtime-core/src/macros.rs @@ -1,3 +1,5 @@ +/// Prints a log message with args, similar to println, when the debug feature is enabled. +/// If the debug feature is disabled, arguments are not evaluated or printed. #[macro_export] #[cfg(feature = "debug")] macro_rules! debug { From 40b1955d997bf04c71c168532aff4dd81d5f10c1 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 11 Nov 2019 11:23:46 -0800 Subject: [PATCH 105/342] Update release pipeline --- azure-pipelines.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index db05b2d340d..28cd830a586 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -220,10 +220,15 @@ jobs: displayName: "Create GitHub Release" condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master')) inputs: - gitHubConnection: wasmer - repositoryName: wasmerio/wasmer - tag: dev - assets: $(Build.ArtifactStagingDirectory) + gitHubConnection: 'wasmer' + repositoryName: 'wasmerio/wasmer' + action: 'create' + target: '$(Build.SourceVersion)' + tagSource: 'auto' + # TODO: automate it all by getting the release notes from somewhere else and using the `releaseNotesFile` key + isDraft: false + isPreRelease: false + assets: '$(Build.ArtifactStagingDirectory)/*' - job: Docs pool: From 0a216c077929b9c4ceb255f1a81fce7809d7fd8e Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 11 Nov 2019 12:13:53 -0800 Subject: [PATCH 106/342] Prepare for 0.10.0 release --- CHANGELOG.md | 7 +- Cargo.lock | 146 ++++++++++++------------- 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 | 8 +- lib/runtime-core-tests/Cargo.toml | 12 +- 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 | 4 +- scripts/update_version_numbers.sh | 4 +- src/installer/wasmer.iss | 2 +- wapm-cli | 2 +- 22 files changed, 141 insertions(+), 136 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d71b7046ec3..3c243a0ef0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,14 @@ ## **[Unreleased]** +## 0.10.0 - 2019-11-11 + +Special thanks to @newpavlov and @Maxgy for their contributions! + - [#942](https://github.com/wasmerio/wasmer/pull/942) Deny missing docs in runtime core and add missing docs -- [#936](https://github.com/wasmerio/wasmer/pull/939) Fix bug causing attempts to append to files with WASI to delete the contents of the file +- [#939](https://github.com/wasmerio/wasmer/pull/939) Fix bug causing attempts to append to files with WASI to delete the contents of the file - [#940](https://github.com/wasmerio/wasmer/pull/940) Update supported Rust version to 1.38+ +- [#923](https://github.com/wasmerio/wasmer/pull/923) Fix memory leak in the C API caused by an incorrect cast in `wasmer_trampoline_buffer_destroy` - [#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 diff --git a/Cargo.lock b/Cargo.lock index 9012e4f6ce8..5e5689214e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -725,8 +725,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.9.0", - "wasmer-runtime-core 0.9.0", + "wasmer-runtime 0.10.0", + "wasmer-runtime-core 0.10.0", ] [[package]] @@ -1338,7 +1338,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wasmer" -version = "0.9.0" +version = "0.10.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)", @@ -1348,24 +1348,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.9.0", - "wasmer-dev-utils 0.9.0", - "wasmer-emscripten 0.9.0", - "wasmer-emscripten-tests 0.9.0", + "wasmer-clif-backend 0.10.0", + "wasmer-dev-utils 0.10.0", + "wasmer-emscripten 0.10.0", + "wasmer-emscripten-tests 0.10.0", "wasmer-kernel-loader 0.1.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", + "wasmer-llvm-backend 0.10.0", + "wasmer-middleware-common 0.10.0", + "wasmer-middleware-common-tests 0.10.0", + "wasmer-runtime 0.10.0", + "wasmer-runtime-core 0.10.0", + "wasmer-singlepass-backend 0.10.0", + "wasmer-wasi 0.10.0", + "wasmer-wasi-tests 0.10.0", ] [[package]] name = "wasmer-clif-backend" -version = "0.9.0" +version = "0.10.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)", @@ -1381,8 +1381,8 @@ 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.9.0", - "wasmer-win-exception-handler 0.9.0", + "wasmer-runtime-core 0.10.0", + "wasmer-win-exception-handler 0.10.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)", ] @@ -1414,35 +1414,35 @@ dependencies = [ [[package]] name = "wasmer-dev-utils" -version = "0.9.0" +version = "0.10.0" dependencies = [ "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmer-emscripten" -version = "0.9.0" +version = "0.10.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)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.9.0", + "wasmer-runtime-core 0.10.0", ] [[package]] name = "wasmer-emscripten-tests" -version = "0.9.0" +version = "0.10.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.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", + "wasmer-clif-backend 0.10.0", + "wasmer-dev-utils 0.10.0", + "wasmer-emscripten 0.10.0", + "wasmer-llvm-backend 0.10.0", + "wasmer-runtime-core 0.10.0", + "wasmer-singlepass-backend 0.10.0", ] [[package]] @@ -1450,12 +1450,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.9.0", + "wasmer-runtime-core 0.10.0", ] [[package]] name = "wasmer-llvm-backend" -version = "0.9.0" +version = "0.10.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)", @@ -1469,60 +1469,60 @@ dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.12 (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", + "wasmer-runtime-core 0.10.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.9.0" +version = "0.10.0" dependencies = [ - "wasmer-runtime-core 0.9.0", + "wasmer-runtime-core 0.10.0", ] [[package]] name = "wasmer-middleware-common-tests" -version = "0.9.0" +version = "0.10.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.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", + "wasmer-clif-backend 0.10.0", + "wasmer-llvm-backend 0.10.0", + "wasmer-middleware-common 0.10.0", + "wasmer-runtime-core 0.10.0", + "wasmer-singlepass-backend 0.10.0", ] [[package]] name = "wasmer-runtime" -version = "0.9.0" +version = "0.10.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.9.0", - "wasmer-llvm-backend 0.9.0", - "wasmer-runtime-core 0.9.0", - "wasmer-singlepass-backend 0.9.0", + "wasmer-clif-backend 0.10.0", + "wasmer-llvm-backend 0.10.0", + "wasmer-runtime-core 0.10.0", + "wasmer-singlepass-backend 0.10.0", ] [[package]] name = "wasmer-runtime-c-api" -version = "0.9.0" +version = "0.10.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.9.0", - "wasmer-runtime-core 0.9.0", - "wasmer-wasi 0.9.0", + "wasmer-runtime 0.10.0", + "wasmer-runtime-core 0.10.0", + "wasmer-wasi 0.10.0", ] [[package]] name = "wasmer-runtime-core" -version = "0.9.0" +version = "0.10.0" dependencies = [ "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)", @@ -1549,18 +1549,18 @@ dependencies = [ [[package]] name = "wasmer-runtime-core-tests" -version = "0.9.0" +version = "0.10.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", + "wasmer-clif-backend 0.10.0", + "wasmer-llvm-backend 0.10.0", + "wasmer-runtime-core 0.10.0", + "wasmer-singlepass-backend 0.10.0", ] [[package]] name = "wasmer-singlepass-backend" -version = "0.9.0" +version = "0.10.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)", @@ -1569,24 +1569,24 @@ 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.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.9.0", + "wasmer-runtime-core 0.10.0", ] [[package]] name = "wasmer-spectests" -version = "0.9.0" +version = "0.10.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.9.0", - "wasmer-llvm-backend 0.9.0", - "wasmer-runtime-core 0.9.0", - "wasmer-singlepass-backend 0.9.0", + "wasmer-clif-backend 0.10.0", + "wasmer-llvm-backend 0.10.0", + "wasmer-runtime-core 0.10.0", + "wasmer-singlepass-backend 0.10.0", ] [[package]] name = "wasmer-wasi" -version = "0.9.0" +version = "0.10.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)", @@ -1597,31 +1597,31 @@ dependencies = [ "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", + "wasmer-runtime-core 0.10.0", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmer-wasi-tests" -version = "0.9.0" +version = "0.10.0" dependencies = [ "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "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", + "wasmer-clif-backend 0.10.0", + "wasmer-dev-utils 0.10.0", + "wasmer-llvm-backend 0.10.0", + "wasmer-runtime 0.10.0", + "wasmer-runtime-core 0.10.0", + "wasmer-singlepass-backend 0.10.0", + "wasmer-wasi 0.10.0", ] [[package]] name = "wasmer-win-exception-handler" -version = "0.9.0" +version = "0.10.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.9.0", + "wasmer-runtime-core 0.10.0", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/Cargo.toml b/Cargo.toml index 0fe11919fb9..c90d8291502 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer" -version = "0.9.0" +version = "0.10.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 22af9de037b..65ec9841ccf 100644 --- a/lib/clif-backend/Cargo.toml +++ b/lib/clif-backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-clif-backend" -version = "0.9.0" +version = "0.10.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.9.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.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.9.0" } +wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.10.0" } [features] debug = ["wasmer-runtime-core/debug"] diff --git a/lib/dev-utils/Cargo.toml b/lib/dev-utils/Cargo.toml index 3bb7c6f4f76..86718b562a4 100644 --- a/lib/dev-utils/Cargo.toml +++ b/lib/dev-utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-dev-utils" -version = "0.9.0" +version = "0.10.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 8f2725f5722..19022cda0ef 100644 --- a/lib/emscripten-tests/Cargo.toml +++ b/lib/emscripten-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-emscripten-tests" -version = "0.9.0" +version = "0.10.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.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 } +wasmer-emscripten = { path = "../emscripten", version = "0.10.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.0" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.10.0" } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.0", optional = true } [dev-dependencies] wabt = "0.9.1" -wasmer-dev-utils = { path = "../dev-utils", version = "0.9.0"} +wasmer-dev-utils = { path = "../dev-utils", version = "0.10.0"} [build-dependencies] glob = "0.3" diff --git a/lib/emscripten/Cargo.toml b/lib/emscripten/Cargo.toml index f51ee1a724b..0f57dce4576 100644 --- a/lib/emscripten/Cargo.toml +++ b/lib/emscripten/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-emscripten" -version = "0.9.0" +version = "0.10.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.9.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.0" } [target.'cfg(windows)'.dependencies] getrandom = "0.1" diff --git a/lib/llvm-backend/Cargo.toml b/lib/llvm-backend/Cargo.toml index 4cd3e247923..dd5b975d7c0 100644 --- a/lib/llvm-backend/Cargo.toml +++ b/lib/llvm-backend/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "wasmer-llvm-backend" -version = "0.9.0" +version = "0.10.0" authors = ["The Wasmer Engineering Team "] edition = "2018" readme = "README.md" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.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 e27bb4a9cf0..6b336c960df 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.9.0" +version = "0.10.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.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 } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.0" } +wasmer-middleware-common = { path = "../middleware-common", version = "0.10.0" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.10.0" } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.0", optional = true } [features] clif = [] diff --git a/lib/middleware-common/Cargo.toml b/lib/middleware-common/Cargo.toml index 3d4def8703c..de54845e870 100644 --- a/lib/middleware-common/Cargo.toml +++ b/lib/middleware-common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-middleware-common" -version = "0.9.0" +version = "0.10.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.9.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.0" } diff --git a/lib/runtime-c-api/Cargo.toml b/lib/runtime-c-api/Cargo.toml index 8d5dbb61401..93d41e1ec64 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.9.0" +version = "0.10.0" description = "Wasmer C API library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -17,17 +17,17 @@ libc = "0.2.60" [dependencies.wasmer-runtime] default-features = false path = "../runtime" -version = "0.9.0" +version = "0.10.0" [dependencies.wasmer-runtime-core] default-features = false path = "../runtime-core" -version = "0.9.0" +version = "0.10.0" [dependencies.wasmer-wasi] default-features = false path = "../wasi" -version = "0.9.0" +version = "0.10.0" optional = true [features] diff --git a/lib/runtime-core-tests/Cargo.toml b/lib/runtime-core-tests/Cargo.toml index d2db29f2bd0..a10cd2b8e86 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.9.0" +version = "0.10.0" description = "Tests for the Wasmer runtime core crate" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -9,13 +9,13 @@ 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 } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.0" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.10.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.0", optional = true } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.0", 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 +backend-llvm = ["wasmer-llvm-backend"] diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml index 7e8e80c5ff3..6f9e09ffb94 100644 --- a/lib/runtime-core/Cargo.toml +++ b/lib/runtime-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-runtime-core" -version = "0.9.0" +version = "0.10.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 d2bcb83a7b9..b8c5ca97116 100644 --- a/lib/runtime/Cargo.toml +++ b/lib/runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-runtime" -version = "0.9.0" +version = "0.10.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.9.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.0", optional = true } lazy_static = "1.4" memmap = "0.7" [dependencies.wasmer-runtime-core] path = "../runtime-core" -version = "0.9.0" +version = "0.10.0" [dependencies.wasmer-clif-backend] path = "../clif-backend" -version = "0.9.0" +version = "0.10.0" optional = true [dev-dependencies] diff --git a/lib/singlepass-backend/Cargo.toml b/lib/singlepass-backend/Cargo.toml index 7abd4a1586a..95e7415a4f3 100644 --- a/lib/singlepass-backend/Cargo.toml +++ b/lib/singlepass-backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-singlepass-backend" -version = "0.9.0" +version = "0.10.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.9.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.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 88df563293d..b6dd1e30544 100644 --- a/lib/spectests/Cargo.toml +++ b/lib/spectests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-spectests" -version = "0.9.0" +version = "0.10.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.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 } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.0" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.10.0" } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.0", optional = true } [build-dependencies] wabt = "0.9.1" diff --git a/lib/wasi-tests/Cargo.toml b/lib/wasi-tests/Cargo.toml index 96626f6cff1..0d17d3d73dd 100644 --- a/lib/wasi-tests/Cargo.toml +++ b/lib/wasi-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-wasi-tests" -version = "0.9.0" +version = "0.10.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.9.0" } -wasmer-runtime = { path = "../runtime", version = "0.9.0" } -wasmer-wasi = { path = "../wasi", version = "0.9.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.0" } +wasmer-runtime = { path = "../runtime", version = "0.10.0" } +wasmer-wasi = { path = "../wasi", version = "0.10.0" } # hack to get tests to work -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.9.0", optional = true } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.9.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.0", optional = true } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.0", optional = true } [build-dependencies] glob = "0.3" [dev-dependencies] -wasmer-clif-backend = { path = "../clif-backend", version = "0.9.0" } -wasmer-dev-utils = { path = "../dev-utils", version = "0.9.0"} +wasmer-clif-backend = { path = "../clif-backend", version = "0.10.0" } +wasmer-dev-utils = { path = "../dev-utils", version = "0.10.0"} [features] clif = [] diff --git a/lib/wasi/Cargo.toml b/lib/wasi/Cargo.toml index e73b57ea474..1e9d670499d 100644 --- a/lib/wasi/Cargo.toml +++ b/lib/wasi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-wasi" -version = "0.9.0" +version = "0.10.0" description = "Wasmer runtime WASI implementation library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -17,7 +17,7 @@ getrandom = "0.1" time = "0.1" typetag = "0.1" serde = { version = "1", features = ["derive"] } -wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.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 b3281c51161..8d914de9574 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.9.0" +version = "0.10.0" description = "Wasmer runtime exception handling for Windows" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -8,7 +8,7 @@ repository = "https://github.com/wasmerio/wasmer" edition = "2018" [target.'cfg(windows)'.dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.0" } winapi = { version = "0.3.8", features = ["winbase", "errhandlingapi", "minwindef", "minwinbase", "winnt"] } libc = "0.2.60" diff --git a/scripts/update_version_numbers.sh b/scripts/update_version_numbers.sh index d93bdefb4be..a147f762f86 100755 --- a/scripts/update_version_numbers.sh +++ b/scripts/update_version_numbers.sh @@ -1,5 +1,5 @@ -PREVIOUS_VERSION='0.8.0' -NEXT_VERSION='0.9.0' +PREVIOUS_VERSION='0.9.0' +NEXT_VERSION='0.10.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 cce60f98468..54b99a6ad1a 100644 --- a/src/installer/wasmer.iss +++ b/src/installer/wasmer.iss @@ -1,6 +1,6 @@ [Setup] AppName=Wasmer -AppVersion=0.9.0 +AppVersion=0.10.0 DefaultDirName={pf}\Wasmer DefaultGroupName=Wasmer Compression=lzma2 diff --git a/wapm-cli b/wapm-cli index b157153568f..17653d11d07 160000 --- a/wapm-cli +++ b/wapm-cli @@ -1 +1 @@ -Subproject commit b157153568fc45f0d01ba8443c54fc3c2ce0cb23 +Subproject commit 17653d11d0717fb831636615dd8695393cf4ae2c From cd6ff0a34ae446047d5a5ca1d93fab285e00d81e Mon Sep 17 00:00:00 2001 From: Mark McCaskey <5770194+MarkMcCaskey@users.noreply.github.com> Date: Mon, 11 Nov 2019 12:18:16 -0800 Subject: [PATCH 107/342] Add links to contributors Co-Authored-By: Syrus Akbary --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c243a0ef0c..9ce32fa4815 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ## 0.10.0 - 2019-11-11 -Special thanks to @newpavlov and @Maxgy for their contributions! +Special thanks to [@newpavlov](https://github.com/newpavlov) and [@Maxgy](https://github.com/Maxgy) for their contributions! - [#942](https://github.com/wasmerio/wasmer/pull/942) Deny missing docs in runtime core and add missing docs - [#939](https://github.com/wasmerio/wasmer/pull/939) Fix bug causing attempts to append to files with WASI to delete the contents of the file From 239e1e054437b4591d44a09a410f7c73cb1a2887 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Mon, 11 Nov 2019 13:31:38 -0800 Subject: [PATCH 108/342] Update azure-pipelines.yml --- azure-pipelines.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 481cd9d4b5c..2bba833d9ed 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -216,6 +216,8 @@ jobs: displayName: List Artifacts env: ARTIFACT_STAGING_DIRECTORY: $(Build.ArtifactStagingDirectory) + - script: VERSION_TAG=`git describe --tags` && echo "##vso[task.setvariable variable=VERSION_TAG]$VERSION_TAG" + displayName: Set the tag name as an environment variable - task: GithubRelease@0 displayName: "Create GitHub Release" condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master')) @@ -224,11 +226,13 @@ jobs: repositoryName: 'wasmerio/wasmer' action: 'create' target: '$(Build.SourceVersion)' + title: '$(VERSION_TAG)' + addChangeLog: false tagSource: 'auto' # TODO: automate it all by getting the release notes from somewhere else and using the `releaseNotesFile` key isDraft: false isPreRelease: false - assets: '$(Build.ArtifactStagingDirectory)/*' + assets: '$(Build.ArtifactStagingDirectory)' - job: Docs pool: From 2343075bd94ef9971da5639dc43b3b7efd47611a Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Mon, 11 Nov 2019 14:14:09 -0800 Subject: [PATCH 109/342] Update azure-pipelines.yml --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2bba833d9ed..a8b571e28a0 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -232,7 +232,7 @@ jobs: # TODO: automate it all by getting the release notes from somewhere else and using the `releaseNotesFile` key isDraft: false isPreRelease: false - assets: '$(Build.ArtifactStagingDirectory)' + assets: '$(Build.ArtifactStagingDirectory)/**' - job: Docs pool: From e121c47f18a1a4518e5615426b5f2a02eb0b50b4 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 11 Nov 2019 14:45:14 -0800 Subject: [PATCH 110/342] Generate C preprocessor code to hide things not on Windows --- CHANGELOG.md | 2 ++ lib/runtime-c-api/build.rs | 22 +++++++++++++++++++++ lib/runtime-c-api/src/lib.rs | 4 +++- lib/runtime-c-api/wasmer.h | 37 ++++++++++++++++++++++++++++++++++++ lib/runtime-c-api/wasmer.hh | 37 ++++++++++++++++++++++++++++++++++++ 5 files changed, 101 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ce32fa4815..4b1c7cf258f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## **[Unreleased]** +- [#952](https://github.com/wasmerio/wasmer/pull/952) Use C preprocessor to properly hide trampoline functions on Windowns and non-x86_64 targets. + ## 0.10.0 - 2019-11-11 Special thanks to [@newpavlov](https://github.com/newpavlov) and [@Maxgy](https://github.com/Maxgy) for their contributions! diff --git a/lib/runtime-c-api/build.rs b/lib/runtime-c-api/build.rs index 1db19a19790..7c518398c63 100644 --- a/lib/runtime-c-api/build.rs +++ b/lib/runtime-c-api/build.rs @@ -12,12 +12,31 @@ fn main() { let mut out_wasmer_header_file = PathBuf::from(&out_dir); out_wasmer_header_file.push("wasmer"); + const WASMER_PRE_HEADER: &str = r#" +#ifndef WASMER_H_MACROS +#define WASMER_H_MACROS +#if MSVC +#ifdef _M_AMD64 +#define ARCH_X86_64 +#endif +#endif + +#if GCC +#ifdef __x86_64__ +#define ARCH_X86_64 +#endif +#endif +#endif // WASMER_H_MACROS +"#; // Generate the C bindings in the `OUT_DIR`. out_wasmer_header_file.set_extension("h"); Builder::new() .with_crate(crate_dir.clone()) .with_language(Language::C) .with_include_guard("WASMER_H") + .with_header(WASMER_PRE_HEADER) + .with_define("target_family", "windows", "_WIN32") + .with_define("target_arch", "x86_64", "ARCH_X86_64") .generate() .expect("Unable to generate C bindings") .write_to_file(out_wasmer_header_file.as_path()); @@ -28,6 +47,9 @@ fn main() { .with_crate(crate_dir) .with_language(Language::Cxx) .with_include_guard("WASMER_H") + .with_header(WASMER_PRE_HEADER) + .with_define("target_family", "windows", "_WIN32") + .with_define("target_arch", "x86_64", "ARCH_X86_64") .generate() .expect("Unable to generate C++ bindings") .write_to_file(out_wasmer_header_file.as_path()); diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 17e96a4c343..f0464075467 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -101,7 +101,9 @@ pub mod instance; pub mod memory; pub mod module; pub mod table; -#[cfg(all(unix, target_arch = "x86_64"))] +// `not(target_family = "windows")` is simpler than `unix`. See build.rs +// if you want to change the meaning of these `cfg`s in the header file. +#[cfg(all(not(target_family = "windows"), target_arch = "x86_64"))] pub mod trampoline; pub mod value; diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index eb9dab50dbc..bc4a3ed4fe6 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -1,3 +1,20 @@ + +#ifndef WASMER_H_MACROS +#define WASMER_H_MACROS +#if MSVC +#ifdef _M_AMD64 +#define ARCH_X86_64 +#endif +#endif + +#if GCC +#ifdef __x86_64__ +#define ARCH_X86_64 +#endif +#endif +#endif // WASMER_H_MACROS + + #ifndef WASMER_H #define WASMER_H @@ -162,17 +179,23 @@ typedef struct { } wasmer_serialized_module_t; +#if (!defined(_WIN32) && defined(ARCH_X86_64)) typedef struct { } wasmer_trampoline_buffer_builder_t; +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) typedef struct { } wasmer_trampoline_callable_t; +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) typedef struct { } wasmer_trampoline_buffer_t; +#endif /** * Opens a directory that's visible to the WASI module as `alias` but @@ -780,6 +803,7 @@ uint32_t wasmer_table_length(wasmer_table_t *table); */ wasmer_result_t wasmer_table_new(wasmer_table_t **table, wasmer_limits_t limits); +#if (!defined(_WIN32) && defined(ARCH_X86_64)) /** * Adds a callinfo trampoline to the builder. */ @@ -787,39 +811,52 @@ uintptr_t wasmer_trampoline_buffer_builder_add_callinfo_trampoline(wasmer_trampo const wasmer_trampoline_callable_t *func, const void *ctx, uint32_t num_params); +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) /** * Adds a context trampoline to the builder. */ uintptr_t wasmer_trampoline_buffer_builder_add_context_trampoline(wasmer_trampoline_buffer_builder_t *builder, const wasmer_trampoline_callable_t *func, const void *ctx); +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) /** * Finalizes the trampoline builder into an executable buffer. */ wasmer_trampoline_buffer_t *wasmer_trampoline_buffer_builder_build(wasmer_trampoline_buffer_builder_t *builder); +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) /** * Creates a new trampoline builder. */ wasmer_trampoline_buffer_builder_t *wasmer_trampoline_buffer_builder_new(void); +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) /** * Destroys the trampoline buffer if not null. */ void wasmer_trampoline_buffer_destroy(wasmer_trampoline_buffer_t *buffer); +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) /** * Returns the callable pointer for the trampoline with index `idx`. */ const wasmer_trampoline_callable_t *wasmer_trampoline_buffer_get_trampoline(const wasmer_trampoline_buffer_t *buffer, uintptr_t idx); +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) /** * Returns the context added by `add_context_trampoline`, from within the callee function. */ void *wasmer_trampoline_get_context(void); +#endif /** * Returns true for valid wasm bytes and false for invalid bytes diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 04a095c4834..acf4b20e797 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -1,3 +1,20 @@ + +#ifndef WASMER_H_MACROS +#define WASMER_H_MACROS +#if MSVC +#ifdef _M_AMD64 +#define ARCH_X86_64 +#endif +#endif + +#if GCC +#ifdef __x86_64__ +#define ARCH_X86_64 +#endif +#endif +#endif // WASMER_H_MACROS + + #ifndef WASMER_H #define WASMER_H @@ -146,17 +163,23 @@ struct wasmer_serialized_module_t { }; +#if (!defined(_WIN32) && defined(ARCH_X86_64)) struct wasmer_trampoline_buffer_builder_t { }; +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) struct wasmer_trampoline_callable_t { }; +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) struct wasmer_trampoline_buffer_t { }; +#endif /// Opens a directory that's visible to the WASI module as `alias` but /// is backed by the host file at `host_file_path` @@ -612,32 +635,46 @@ uint32_t wasmer_table_length(wasmer_table_t *table); /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_table_new(wasmer_table_t **table, wasmer_limits_t limits); +#if (!defined(_WIN32) && defined(ARCH_X86_64)) /// Adds a callinfo trampoline to the builder. uintptr_t wasmer_trampoline_buffer_builder_add_callinfo_trampoline(wasmer_trampoline_buffer_builder_t *builder, const wasmer_trampoline_callable_t *func, const void *ctx, uint32_t num_params); +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) /// Adds a context trampoline to the builder. uintptr_t wasmer_trampoline_buffer_builder_add_context_trampoline(wasmer_trampoline_buffer_builder_t *builder, const wasmer_trampoline_callable_t *func, const void *ctx); +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) /// Finalizes the trampoline builder into an executable buffer. wasmer_trampoline_buffer_t *wasmer_trampoline_buffer_builder_build(wasmer_trampoline_buffer_builder_t *builder); +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) /// Creates a new trampoline builder. wasmer_trampoline_buffer_builder_t *wasmer_trampoline_buffer_builder_new(); +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) /// Destroys the trampoline buffer if not null. void wasmer_trampoline_buffer_destroy(wasmer_trampoline_buffer_t *buffer); +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) /// Returns the callable pointer for the trampoline with index `idx`. const wasmer_trampoline_callable_t *wasmer_trampoline_buffer_get_trampoline(const wasmer_trampoline_buffer_t *buffer, uintptr_t idx); +#endif +#if (!defined(_WIN32) && defined(ARCH_X86_64)) /// Returns the context added by `add_context_trampoline`, from within the callee function. void *wasmer_trampoline_get_context(); +#endif /// Returns true for valid wasm bytes and false for invalid bytes bool wasmer_validate(const uint8_t *wasm_bytes, uint32_t wasm_bytes_len); From 08c66d6b777b1bbaf8f097b5faeb0754b9e75663 Mon Sep 17 00:00:00 2001 From: nlewycky Date: Mon, 11 Nov 2019 14:52:17 -0800 Subject: [PATCH 111/342] Fix typo. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b1c7cf258f..8acac077215 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## **[Unreleased]** -- [#952](https://github.com/wasmerio/wasmer/pull/952) Use C preprocessor to properly hide trampoline functions on Windowns and non-x86_64 targets. +- [#952](https://github.com/wasmerio/wasmer/pull/952) Use C preprocessor to properly hide trampoline functions on Windows and non-x86_64 targets. ## 0.10.0 - 2019-11-11 From 98e4ef066a0354a3efdbfe2af0eeeb0101e8ff57 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 11 Nov 2019 21:45:46 +0100 Subject: [PATCH 112/342] feat(runtime-core) Feed imported functions with `vm::Ctx` again. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … and look for the associated `vm::FuncCtx`. This way, we don't break the rule: “all functions receive a vmctx pointer as first argument.”. --- lib/clif-backend/src/code.rs | 19 +++++++++++--- lib/runtime-core/src/typed_func.rs | 42 ++++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index d07b5ce6dda..157187e77b6 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -691,7 +691,9 @@ impl FuncEnvironment for FunctionEnvironment { } /// Generates a call IR with `callee` and `call_args` and inserts it at `pos` - /// TODO: add support for imported functions + /// + /// It's about generating code that calls a local or imported function; in + /// WebAssembly: `(call $foo)`. fn translate_call( &mut self, mut pos: FuncCursor, @@ -771,14 +773,23 @@ impl FuncEnvironment for FunctionEnvironment { readonly: true, }); + let imported_func_ctx_vmctx_addr = + pos.func.create_global_value(ir::GlobalValueData::Load { + base: imported_func_ctx_addr, + offset: (0 as i32).into(), + global_type: ptr_type, + readonly: true, + }); + let imported_func_addr = pos.ins().global_value(ptr_type, imported_func_addr); - let imported_func_ctx_addr = - pos.ins().global_value(ptr_type, imported_func_ctx_addr); + let imported_func_ctx_vmctx_addr = pos + .ins() + .global_value(ptr_type, imported_func_ctx_vmctx_addr); let sig_ref = pos.func.dfg.ext_funcs[callee].signature; let mut args = Vec::with_capacity(call_args.len() + 1); - args.push(imported_func_ctx_addr); + args.push(imported_func_ctx_vmctx_addr); args.extend(call_args.iter().cloned()); Ok(pos diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 7bb7e63cccb..0402856162c 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -502,7 +502,7 @@ macro_rules! impl_traits { // able to unwind through this function. #[cfg_attr(nightly, unwind(allowed))] extern fn wrap<$( $x, )* Rets, Trap, FN>( - func_ctx: &mut vm::FuncCtx $( , $x: <$x as WasmExternType>::Native )* + vmctx: &vm::Ctx $( , $x: <$x as WasmExternType>::Native )* ) -> Rets::CStruct where $( $x: WasmExternType, )* @@ -510,6 +510,25 @@ macro_rules! impl_traits { Trap: TrapEarly, FN: Fn(&mut vm::Ctx, $( $x, )*) -> Trap, { + // Get the pointer to this `wrap` function. + let self_pointer = wrap::<$( $x, )* Rets, Trap, FN> as *const vm::Func; + + // Get the collection of imported functions. + let vm_imported_functions = unsafe { &(*vmctx.import_backing).vm_functions }; + + // Retrieve the `vm::FuncCtx`. + let mut func_ctx: NonNull = vm_imported_functions + .iter() + .find_map(|(_, imported_func)| { + if imported_func.func == self_pointer { + Some(imported_func.func_ctx) + } else { + None + } + }) + .expect("Import backing is not well-formed, cannot find `func_ctx`."); + let func_ctx = unsafe { func_ctx.as_mut() }; + // Extract `vm::Ctx` from `vm::FuncCtx`. The // pointer is always non-null. let vmctx = unsafe { func_ctx.vmctx.as_mut() }; @@ -598,7 +617,7 @@ macro_rules! impl_traits { // able to unwind through this function. #[cfg_attr(nightly, unwind(allowed))] extern fn wrap<$( $x, )* Rets, Trap, FN>( - func_ctx: &mut vm::FuncCtx $( , $x: <$x as WasmExternType>::Native )* + vmctx: &vm::Ctx $( , $x: <$x as WasmExternType>::Native )* ) -> Rets::CStruct where $( $x: WasmExternType, )* @@ -606,6 +625,25 @@ macro_rules! impl_traits { Trap: TrapEarly, FN: Fn($( $x, )*) -> Trap, { + // Get the pointer to this `wrap` function. + let self_pointer = wrap::<$( $x, )* Rets, Trap, FN> as *const vm::Func; + + // Get the collection of imported functions. + let vm_imported_functions = unsafe { &(*vmctx.import_backing).vm_functions }; + + // Retrieve the `vm::FuncCtx`. + let mut func_ctx: NonNull = vm_imported_functions + .iter() + .find_map(|(_, imported_func)| { + if imported_func.func == self_pointer { + Some(imported_func.func_ctx) + } else { + None + } + }) + .expect("Import backing is not well-formed, cannot find `func_ctx`."); + let func_ctx = unsafe { func_ctx.as_mut() }; + // Extract `vm::Ctx` from `vm::FuncCtx`. The // pointer is always non-null. let vmctx = unsafe { func_ctx.vmctx.as_mut() }; From 11f34a92854196b867b6c9c99324dbcdc6ad14bb Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 11 Nov 2019 23:12:40 +0100 Subject: [PATCH 113/342] feat(clif-backend,singlepass-backend) Feed imported functions with `FuncCtx.vmctx`. --- lib/clif-backend/src/code.rs | 2 +- lib/runtime-core/src/vm.rs | 33 +++++++++++++++++++++-- lib/singlepass-backend/src/codegen_x64.rs | 6 +++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index 157187e77b6..1bd1958e3de 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -776,7 +776,7 @@ impl FuncEnvironment for FunctionEnvironment { let imported_func_ctx_vmctx_addr = pos.func.create_global_value(ir::GlobalValueData::Load { base: imported_func_ctx_addr, - offset: (0 as i32).into(), + offset: (vm::FuncCtx::offset_vmctx() as i32).into(), global_type: ptr_type, readonly: true, }); diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index 1c9a8b7add4..6f9ff5c47ac 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -518,7 +518,7 @@ pub struct FuncEnv { /// only. #[derive(Debug)] #[repr(C)] -pub(crate) struct FuncCtx { +pub struct FuncCtx { /// The `Ctx` pointer. pub(crate) vmctx: NonNull, @@ -529,6 +529,20 @@ pub(crate) struct FuncCtx { pub(crate) func_env: Option>, } +impl FuncCtx { + pub fn offset_vmctx() -> u8 { + 0 * (mem::size_of::() as u8) + } + + pub fn offset_func_env() -> u8 { + 1 * (mem::size_of::() as u8) + } + + pub fn size() -> u8 { + mem::size_of::() as u8 + } +} + /// An imported function is a function pointer associated to a /// function context. #[derive(Debug, Clone)] @@ -687,7 +701,9 @@ impl Anyfunc { #[cfg(test)] mod vm_offset_tests { - use super::{Anyfunc, Ctx, ImportedFunc, InternalCtx, LocalGlobal, LocalMemory, LocalTable}; + use super::{ + Anyfunc, Ctx, FuncCtx, ImportedFunc, InternalCtx, LocalGlobal, LocalMemory, LocalTable, + }; #[test] fn vmctx() { @@ -764,6 +780,19 @@ mod vm_offset_tests { ); } + #[test] + fn func_ctx() { + assert_eq!( + FuncCtx::offset_vmctx() as usize, + offset_of!(FuncCtx => vmctx).get_byte_offset(), + ); + + assert_eq!( + FuncCtx::offset_func_env() as usize, + offset_of!(FuncCtx => func_env).get_byte_offset(), + ); + } + #[test] fn imported_func() { assert_eq!( diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 3ee60babf4f..7a71a289fe2 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -558,6 +558,7 @@ impl ModuleCodeGenerator let imported_func = vm::ImportedFunc::size() as usize * id; let imported_func_addr = imported_func + vm::ImportedFunc::offset_func() as usize; let imported_func_ctx_addr = imported_func + vm::ImportedFunc::offset_func_ctx() as usize; + let imported_func_ctx_vmctx_addr = vm::FuncCtx::offset_vmctx() as usize; a.emit_mov( Size::S64, @@ -569,6 +570,11 @@ impl ModuleCodeGenerator Location::Memory(GPR::RAX, imported_func_ctx_addr as i32), Location::GPR(GPR::RDI), ); + a.emit_mov( + Size::S64, + Location::Memory(GPR::RDI, imported_func_ctx_vmctx_addr as i32), + Location::GPR(GPR::RDI), + ); a.emit_mov( Size::S64, Location::Memory(GPR::RAX, imported_func_addr as i32), From 06c6b3c8e8872c6257154f416128d342c6bcf243 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 11 Nov 2019 23:49:10 +0100 Subject: [PATCH 114/342] feat(runtime-core) More ABI compatible definition of `Func` and `FuncEnv`. --- lib/runtime-core/src/vm.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index 6f9ff5c47ac..27b84fd0379 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -501,18 +501,14 @@ impl Ctx { /// Represents a function pointer. It is mostly used in the /// `typed_func` module within the `wrap` functions, to wrap imported /// functions. -#[repr(C)] -pub struct Func { - _private: [u8; 0], -} +#[repr(transparent)] +pub struct Func(pub(self) *mut c_void); /// Represents a function environment pointer, like a captured /// environment of a closure. It is mostly used in the `typed_func` /// module within the `wrap` functions, to wrap imported functions. -#[repr(C)] -pub struct FuncEnv { - _private: [u8; 0], -} +#[repr(transparent)] +pub struct FuncEnv(pub(self) *mut c_void); /// Represents a function context. It is used by imported functions /// only. From bb81614be4187767bb6e0d56c184fa8ca4fcdcac Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 12 Nov 2019 00:46:28 +0100 Subject: [PATCH 115/342] feat(llvm-backend) Update `ImportedFunc` structure. `vm::ImportedFunc` in `runtime-core` has changed. Update LLVM accordingly. --- lib/llvm-backend/src/intrinsics.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index 4c34b6d584a..58de337b082 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -210,8 +210,13 @@ impl Intrinsics { context.struct_type(&[i8_ptr_ty_basic, i64_ty_basic, i8_ptr_ty_basic], false); let local_table_ty = local_memory_ty; let local_global_ty = i64_ty; - let imported_func_ty = - context.struct_type(&[i8_ptr_ty_basic, ctx_ptr_ty.as_basic_type_enum()], false); + let func_ctx_ty = + context.struct_type(&[ctx_ptr_ty.as_basic_type_enum(), i8_ptr_ty_basic], false); + let func_ctx_ptr_ty = func_ctx_ty.ptr_type(AddressSpace::Generic); + let imported_func_ty = context.struct_type( + &[i8_ptr_ty_basic, func_ctx_ptr_ty.as_basic_type_enum()], + false, + ); let sigindex_ty = i32_ty; let rt_intrinsics_ty = i8_ty; let stack_lower_bound_ty = i8_ty; @@ -1118,16 +1123,20 @@ impl<'a> CtxType<'a> { "imported_func_ptr", ) }; - let (func_ptr_ptr, ctx_ptr_ptr) = unsafe { + let (func_ptr_ptr, func_ctx_ptr_ptr) = unsafe { ( cache_builder.build_struct_gep(imported_func_ptr, 0, "func_ptr_ptr"), - cache_builder.build_struct_gep(imported_func_ptr, 1, "ctx_ptr_ptr"), + cache_builder.build_struct_gep(imported_func_ptr, 1, "func_ctx_ptr_ptr"), ) }; let func_ptr = cache_builder .build_load(func_ptr_ptr, "func_ptr") .into_pointer_value(); + let func_ctx_ptr = cache_builder + .build_load(func_ctx_ptr_ptr, "func_ctx_ptr") + .into_pointer_value(); + let ctx_ptr_ptr = unsafe { cache_builder.build_struct_gep(func_ctx_ptr, 0, "ctx_ptr") }; let ctx_ptr = cache_builder .build_load(ctx_ptr_ptr, "ctx_ptr") .into_pointer_value(); From f002f03e5d2269221b65d2eaca42084dc71a45d6 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 12 Nov 2019 00:56:34 +0100 Subject: [PATCH 116/342] chore(changelog) Fix CS. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fb6714f6e7..efb2b1beac3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - [#925](https://github.com/wasmerio/wasmer/pull/925) Host functions can be closures with a captured environment. - [#917](https://github.com/wasmerio/wasmer/pull/917) Host functions (aka imported functions) may not have `&mut vm::Ctx` as first argument, i.e. the presence of the `&mut vm::Ctx` argument is optional. - [#915](https://github.com/wasmerio/wasmer/pull/915) All backends share the same definition of `Trampoline` (defined in `wasmer-runtime-core`). + ## 0.10.0 - 2019-11-11 Special thanks to [@newpavlov](https://github.com/newpavlov) and [@Maxgy](https://github.com/Maxgy) for their contributions! From 22abd8efdcc120cdc24de51de3f8931c84d3c4dd Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 12 Nov 2019 01:10:32 +0100 Subject: [PATCH 117/342] doc(runtime-core) Add missing doc on `vm::FuncCtx`. --- lib/runtime-core/src/vm.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index 1ec0a3da519..ea63c47fc97 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -551,14 +551,17 @@ pub struct FuncCtx { } impl FuncCtx { + /// Offset to `vmctx`. pub fn offset_vmctx() -> u8 { 0 * (mem::size_of::() as u8) } + /// Offset to `func_env`. pub fn offset_func_env() -> u8 { 1 * (mem::size_of::() as u8) } + /// Size of a `FuncCtx`. pub fn size() -> u8 { mem::size_of::() as u8 } From 69950d9e5f15fce1daf51ae8ec7c43083964fc0d Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 11 Nov 2019 16:21:46 -0800 Subject: [PATCH 118/342] Prepare for 0.10.1 release --- CHANGELOG.md | 2 + Cargo.lock | 146 ++++++++++++------------- 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 | 8 +- lib/runtime-core-tests/Cargo.toml | 10 +- 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 | 4 +- scripts/update_version_numbers.sh | 4 +- src/installer/wasmer.iss | 2 +- wapm-cli | 2 +- 22 files changed, 136 insertions(+), 134 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8acac077215..9efec44fdb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## **[Unreleased]** +## 0.10.0 - 2019-11-11 + - [#952](https://github.com/wasmerio/wasmer/pull/952) Use C preprocessor to properly hide trampoline functions on Windows and non-x86_64 targets. ## 0.10.0 - 2019-11-11 diff --git a/Cargo.lock b/Cargo.lock index 5e5689214e2..0720c9eebbd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -725,8 +725,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.10.0", - "wasmer-runtime-core 0.10.0", + "wasmer-runtime 0.10.1", + "wasmer-runtime-core 0.10.1", ] [[package]] @@ -1338,7 +1338,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wasmer" -version = "0.10.0" +version = "0.10.1" 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)", @@ -1348,24 +1348,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.10.0", - "wasmer-dev-utils 0.10.0", - "wasmer-emscripten 0.10.0", - "wasmer-emscripten-tests 0.10.0", + "wasmer-clif-backend 0.10.1", + "wasmer-dev-utils 0.10.1", + "wasmer-emscripten 0.10.1", + "wasmer-emscripten-tests 0.10.1", "wasmer-kernel-loader 0.1.0", - "wasmer-llvm-backend 0.10.0", - "wasmer-middleware-common 0.10.0", - "wasmer-middleware-common-tests 0.10.0", - "wasmer-runtime 0.10.0", - "wasmer-runtime-core 0.10.0", - "wasmer-singlepass-backend 0.10.0", - "wasmer-wasi 0.10.0", - "wasmer-wasi-tests 0.10.0", + "wasmer-llvm-backend 0.10.1", + "wasmer-middleware-common 0.10.1", + "wasmer-middleware-common-tests 0.10.1", + "wasmer-runtime 0.10.1", + "wasmer-runtime-core 0.10.1", + "wasmer-singlepass-backend 0.10.1", + "wasmer-wasi 0.10.1", + "wasmer-wasi-tests 0.10.1", ] [[package]] name = "wasmer-clif-backend" -version = "0.10.0" +version = "0.10.1" 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)", @@ -1381,8 +1381,8 @@ 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.10.0", - "wasmer-win-exception-handler 0.10.0", + "wasmer-runtime-core 0.10.1", + "wasmer-win-exception-handler 0.10.1", "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)", ] @@ -1414,35 +1414,35 @@ dependencies = [ [[package]] name = "wasmer-dev-utils" -version = "0.10.0" +version = "0.10.1" dependencies = [ "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmer-emscripten" -version = "0.10.0" +version = "0.10.1" 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)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.10.0", + "wasmer-runtime-core 0.10.1", ] [[package]] name = "wasmer-emscripten-tests" -version = "0.10.0" +version = "0.10.1" 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.10.0", - "wasmer-dev-utils 0.10.0", - "wasmer-emscripten 0.10.0", - "wasmer-llvm-backend 0.10.0", - "wasmer-runtime-core 0.10.0", - "wasmer-singlepass-backend 0.10.0", + "wasmer-clif-backend 0.10.1", + "wasmer-dev-utils 0.10.1", + "wasmer-emscripten 0.10.1", + "wasmer-llvm-backend 0.10.1", + "wasmer-runtime-core 0.10.1", + "wasmer-singlepass-backend 0.10.1", ] [[package]] @@ -1450,12 +1450,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.10.0", + "wasmer-runtime-core 0.10.1", ] [[package]] name = "wasmer-llvm-backend" -version = "0.10.0" +version = "0.10.1" 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)", @@ -1469,60 +1469,60 @@ dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.12 (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.10.0", + "wasmer-runtime-core 0.10.1", "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.10.0" +version = "0.10.1" dependencies = [ - "wasmer-runtime-core 0.10.0", + "wasmer-runtime-core 0.10.1", ] [[package]] name = "wasmer-middleware-common-tests" -version = "0.10.0" +version = "0.10.1" 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.10.0", - "wasmer-llvm-backend 0.10.0", - "wasmer-middleware-common 0.10.0", - "wasmer-runtime-core 0.10.0", - "wasmer-singlepass-backend 0.10.0", + "wasmer-clif-backend 0.10.1", + "wasmer-llvm-backend 0.10.1", + "wasmer-middleware-common 0.10.1", + "wasmer-runtime-core 0.10.1", + "wasmer-singlepass-backend 0.10.1", ] [[package]] name = "wasmer-runtime" -version = "0.10.0" +version = "0.10.1" 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.10.0", - "wasmer-llvm-backend 0.10.0", - "wasmer-runtime-core 0.10.0", - "wasmer-singlepass-backend 0.10.0", + "wasmer-clif-backend 0.10.1", + "wasmer-llvm-backend 0.10.1", + "wasmer-runtime-core 0.10.1", + "wasmer-singlepass-backend 0.10.1", ] [[package]] name = "wasmer-runtime-c-api" -version = "0.10.0" +version = "0.10.1" 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.10.0", - "wasmer-runtime-core 0.10.0", - "wasmer-wasi 0.10.0", + "wasmer-runtime 0.10.1", + "wasmer-runtime-core 0.10.1", + "wasmer-wasi 0.10.1", ] [[package]] name = "wasmer-runtime-core" -version = "0.10.0" +version = "0.10.1" dependencies = [ "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)", @@ -1549,18 +1549,18 @@ dependencies = [ [[package]] name = "wasmer-runtime-core-tests" -version = "0.10.0" +version = "0.10.1" dependencies = [ "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-clif-backend 0.10.0", - "wasmer-llvm-backend 0.10.0", - "wasmer-runtime-core 0.10.0", - "wasmer-singlepass-backend 0.10.0", + "wasmer-clif-backend 0.10.1", + "wasmer-llvm-backend 0.10.1", + "wasmer-runtime-core 0.10.1", + "wasmer-singlepass-backend 0.10.1", ] [[package]] name = "wasmer-singlepass-backend" -version = "0.10.0" +version = "0.10.1" 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)", @@ -1569,24 +1569,24 @@ 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.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.10.0", + "wasmer-runtime-core 0.10.1", ] [[package]] name = "wasmer-spectests" -version = "0.10.0" +version = "0.10.1" 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.10.0", - "wasmer-llvm-backend 0.10.0", - "wasmer-runtime-core 0.10.0", - "wasmer-singlepass-backend 0.10.0", + "wasmer-clif-backend 0.10.1", + "wasmer-llvm-backend 0.10.1", + "wasmer-runtime-core 0.10.1", + "wasmer-singlepass-backend 0.10.1", ] [[package]] name = "wasmer-wasi" -version = "0.10.0" +version = "0.10.1" 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)", @@ -1597,31 +1597,31 @@ dependencies = [ "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.10.0", + "wasmer-runtime-core 0.10.1", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmer-wasi-tests" -version = "0.10.0" +version = "0.10.1" dependencies = [ "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-clif-backend 0.10.0", - "wasmer-dev-utils 0.10.0", - "wasmer-llvm-backend 0.10.0", - "wasmer-runtime 0.10.0", - "wasmer-runtime-core 0.10.0", - "wasmer-singlepass-backend 0.10.0", - "wasmer-wasi 0.10.0", + "wasmer-clif-backend 0.10.1", + "wasmer-dev-utils 0.10.1", + "wasmer-llvm-backend 0.10.1", + "wasmer-runtime 0.10.1", + "wasmer-runtime-core 0.10.1", + "wasmer-singlepass-backend 0.10.1", + "wasmer-wasi 0.10.1", ] [[package]] name = "wasmer-win-exception-handler" -version = "0.10.0" +version = "0.10.1" 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.10.0", + "wasmer-runtime-core 0.10.1", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/Cargo.toml b/Cargo.toml index c90d8291502..3d0c6b7addd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer" -version = "0.10.0" +version = "0.10.1" 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 65ec9841ccf..ff83c131541 100644 --- a/lib/clif-backend/Cargo.toml +++ b/lib/clif-backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-clif-backend" -version = "0.10.0" +version = "0.10.1" 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.10.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } 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.10.0" } +wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.10.1" } [features] debug = ["wasmer-runtime-core/debug"] diff --git a/lib/dev-utils/Cargo.toml b/lib/dev-utils/Cargo.toml index 86718b562a4..9dc98607a74 100644 --- a/lib/dev-utils/Cargo.toml +++ b/lib/dev-utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-dev-utils" -version = "0.10.0" +version = "0.10.1" 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 19022cda0ef..8cb8248f4ad 100644 --- a/lib/emscripten-tests/Cargo.toml +++ b/lib/emscripten-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-emscripten-tests" -version = "0.10.0" +version = "0.10.1" 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.10.0" } -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.0" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.10.0" } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.0", optional = true } -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.0", optional = true } +wasmer-emscripten = { path = "../emscripten", version = "0.10.1" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.10.1" } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.1", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.1", optional = true } [dev-dependencies] wabt = "0.9.1" -wasmer-dev-utils = { path = "../dev-utils", version = "0.10.0"} +wasmer-dev-utils = { path = "../dev-utils", version = "0.10.1"} [build-dependencies] glob = "0.3" diff --git a/lib/emscripten/Cargo.toml b/lib/emscripten/Cargo.toml index 0f57dce4576..104312256f3 100644 --- a/lib/emscripten/Cargo.toml +++ b/lib/emscripten/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-emscripten" -version = "0.10.0" +version = "0.10.1" 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.10.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } [target.'cfg(windows)'.dependencies] getrandom = "0.1" diff --git a/lib/llvm-backend/Cargo.toml b/lib/llvm-backend/Cargo.toml index dd5b975d7c0..b9c851b07e8 100644 --- a/lib/llvm-backend/Cargo.toml +++ b/lib/llvm-backend/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "wasmer-llvm-backend" -version = "0.10.0" +version = "0.10.1" authors = ["The Wasmer Engineering Team "] edition = "2018" readme = "README.md" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } 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 6b336c960df..c55a5a37a6b 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.10.0" +version = "0.10.1" 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.10.0" } -wasmer-middleware-common = { path = "../middleware-common", version = "0.10.0" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.10.0" } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.0", optional = true } -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.0", optional = true } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } +wasmer-middleware-common = { path = "../middleware-common", version = "0.10.1" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.10.1" } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.1", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.1", optional = true } [features] clif = [] diff --git a/lib/middleware-common/Cargo.toml b/lib/middleware-common/Cargo.toml index de54845e870..5840729d632 100644 --- a/lib/middleware-common/Cargo.toml +++ b/lib/middleware-common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-middleware-common" -version = "0.10.0" +version = "0.10.1" 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.10.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } diff --git a/lib/runtime-c-api/Cargo.toml b/lib/runtime-c-api/Cargo.toml index 93d41e1ec64..cc689e8892d 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.10.0" +version = "0.10.1" description = "Wasmer C API library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -17,17 +17,17 @@ libc = "0.2.60" [dependencies.wasmer-runtime] default-features = false path = "../runtime" -version = "0.10.0" +version = "0.10.1" [dependencies.wasmer-runtime-core] default-features = false path = "../runtime-core" -version = "0.10.0" +version = "0.10.1" [dependencies.wasmer-wasi] default-features = false path = "../wasi" -version = "0.10.0" +version = "0.10.1" optional = true [features] diff --git a/lib/runtime-core-tests/Cargo.toml b/lib/runtime-core-tests/Cargo.toml index a10cd2b8e86..73cbb03ce4e 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.10.0" +version = "0.10.1" description = "Tests for the Wasmer runtime core crate" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -9,10 +9,10 @@ publish = false [dependencies] wabt = "0.9.1" -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.0" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.10.0", optional = true } -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.0", optional = true } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.0", optional = true } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.10.1", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.1", optional = true } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.1", optional = true } [features] default = ["backend-cranelift"] diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml index 6f9e09ffb94..0acbe718ede 100644 --- a/lib/runtime-core/Cargo.toml +++ b/lib/runtime-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-runtime-core" -version = "0.10.0" +version = "0.10.1" 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 b8c5ca97116..6e6be013cd0 100644 --- a/lib/runtime/Cargo.toml +++ b/lib/runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-runtime" -version = "0.10.0" +version = "0.10.1" 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.10.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.1", optional = true } lazy_static = "1.4" memmap = "0.7" [dependencies.wasmer-runtime-core] path = "../runtime-core" -version = "0.10.0" +version = "0.10.1" [dependencies.wasmer-clif-backend] path = "../clif-backend" -version = "0.10.0" +version = "0.10.1" optional = true [dev-dependencies] diff --git a/lib/singlepass-backend/Cargo.toml b/lib/singlepass-backend/Cargo.toml index 95e7415a4f3..291d44455c9 100644 --- a/lib/singlepass-backend/Cargo.toml +++ b/lib/singlepass-backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-singlepass-backend" -version = "0.10.0" +version = "0.10.1" 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.10.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } 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 b6dd1e30544..82e5aca2436 100644 --- a/lib/spectests/Cargo.toml +++ b/lib/spectests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-spectests" -version = "0.10.0" +version = "0.10.1" 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.10.0" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.10.0" } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.0", optional = true } -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.0", optional = true } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.10.1" } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.1", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.1", optional = true } [build-dependencies] wabt = "0.9.1" diff --git a/lib/wasi-tests/Cargo.toml b/lib/wasi-tests/Cargo.toml index 0d17d3d73dd..35aa31c0ea5 100644 --- a/lib/wasi-tests/Cargo.toml +++ b/lib/wasi-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-wasi-tests" -version = "0.10.0" +version = "0.10.1" 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.10.0" } -wasmer-runtime = { path = "../runtime", version = "0.10.0" } -wasmer-wasi = { path = "../wasi", version = "0.10.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } +wasmer-runtime = { path = "../runtime", version = "0.10.1" } +wasmer-wasi = { path = "../wasi", version = "0.10.1" } # hack to get tests to work -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.0", optional = true } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.1", optional = true } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.1", optional = true } [build-dependencies] glob = "0.3" [dev-dependencies] -wasmer-clif-backend = { path = "../clif-backend", version = "0.10.0" } -wasmer-dev-utils = { path = "../dev-utils", version = "0.10.0"} +wasmer-clif-backend = { path = "../clif-backend", version = "0.10.1" } +wasmer-dev-utils = { path = "../dev-utils", version = "0.10.1"} [features] clif = [] diff --git a/lib/wasi/Cargo.toml b/lib/wasi/Cargo.toml index 1e9d670499d..8a85acc2d07 100644 --- a/lib/wasi/Cargo.toml +++ b/lib/wasi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-wasi" -version = "0.10.0" +version = "0.10.1" description = "Wasmer runtime WASI implementation library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -17,7 +17,7 @@ getrandom = "0.1" time = "0.1" typetag = "0.1" serde = { version = "1", features = ["derive"] } -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } [target.'cfg(windows)'.dependencies] winapi = "0.3" diff --git a/lib/win-exception-handler/Cargo.toml b/lib/win-exception-handler/Cargo.toml index 8d914de9574..4c0332e5348 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.10.0" +version = "0.10.1" description = "Wasmer runtime exception handling for Windows" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -8,7 +8,7 @@ repository = "https://github.com/wasmerio/wasmer" edition = "2018" [target.'cfg(windows)'.dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } winapi = { version = "0.3.8", features = ["winbase", "errhandlingapi", "minwindef", "minwinbase", "winnt"] } libc = "0.2.60" diff --git a/scripts/update_version_numbers.sh b/scripts/update_version_numbers.sh index a147f762f86..7a8585bfba9 100755 --- a/scripts/update_version_numbers.sh +++ b/scripts/update_version_numbers.sh @@ -1,5 +1,5 @@ -PREVIOUS_VERSION='0.9.0' -NEXT_VERSION='0.10.0' +PREVIOUS_VERSION='0.10.0' +NEXT_VERSION='0.10.1' # 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 54b99a6ad1a..3279cd9f1d8 100644 --- a/src/installer/wasmer.iss +++ b/src/installer/wasmer.iss @@ -1,6 +1,6 @@ [Setup] AppName=Wasmer -AppVersion=0.10.0 +AppVersion=0.10.1 DefaultDirName={pf}\Wasmer DefaultGroupName=Wasmer Compression=lzma2 diff --git a/wapm-cli b/wapm-cli index 17653d11d07..c2da5cda3b8 160000 --- a/wapm-cli +++ b/wapm-cli @@ -1 +1 @@ -Subproject commit 17653d11d0717fb831636615dd8695393cf4ae2c +Subproject commit c2da5cda3b8f9cf7dcea144f8cabdf342f38a0bf From 91b505950664ae403a176ee08aa62e064a4bd0c7 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Mon, 11 Nov 2019 20:05:04 -0600 Subject: [PATCH 119/342] Deny missing docs in the clif backend crate --- lib/clif-backend/src/lib.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/clif-backend/src/lib.rs b/lib/clif-backend/src/lib.rs index ddecdbaf08a..06bffc791cc 100644 --- a/lib/clif-backend/src/lib.rs +++ b/lib/clif-backend/src/lib.rs @@ -1,5 +1,10 @@ +//! The Wasmer Cranelift Backend crate is used to compile wasm binary code via parse events from the +//! Wasmer runtime common parser code into machine code. +//! + #![deny( dead_code, + missing_docs, nonstandard_style, unused_imports, unused_mut, @@ -53,6 +58,8 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION"); use wasmer_runtime_core::codegen::SimpleStreamingCompilerGen; +/// Streaming compiler implementation for the Cranelift backed. Compiles web assembly binary into +/// machine code. pub type CraneliftCompiler = SimpleStreamingCompilerGen< code::CraneliftModuleCodeGenerator, code::CraneliftFunctionCodeGenerator, From 0de7f4fd0b52ee2888a88f4f45fc68c5f6ebcb2f Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 12 Nov 2019 14:34:55 +0100 Subject: [PATCH 120/342] test(runtime-core) `offset_of!` fails with a struct containing `NonNull` types. It fails only in release mode. That's a bug from the `field-offset` crate. This patch is a temporary fix. --- lib/runtime-core/src/vm.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index ea63c47fc97..7dfb7de2ba2 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -831,15 +831,9 @@ mod vm_offset_tests { #[test] fn func_ctx() { - assert_eq!( - FuncCtx::offset_vmctx() as usize, - offset_of!(FuncCtx => vmctx).get_byte_offset(), - ); + assert_eq!(FuncCtx::offset_vmctx() as usize, 0,); - assert_eq!( - FuncCtx::offset_func_env() as usize, - offset_of!(FuncCtx => func_env).get_byte_offset(), - ); + assert_eq!(FuncCtx::offset_func_env() as usize, 8,); } #[test] From 5d6c74bfaa1d31a5a5c05e9122386c938920bebe Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 12 Nov 2019 14:37:18 +0100 Subject: [PATCH 121/342] doc(changelog) Fix last release number, and fix CS. --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f9c5400494..a3bcfcd9518 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,8 @@ - [#925](https://github.com/wasmerio/wasmer/pull/925) Host functions can be closures with a captured environment. - [#917](https://github.com/wasmerio/wasmer/pull/917) Host functions (aka imported functions) may not have `&mut vm::Ctx` as first argument, i.e. the presence of the `&mut vm::Ctx` argument is optional. - [#915](https://github.com/wasmerio/wasmer/pull/915) All backends share the same definition of `Trampoline` (defined in `wasmer-runtime-core`). -## 0.10.0 - 2019-11-11 + +## 0.10.1 - 2019-11-11 - [#952](https://github.com/wasmerio/wasmer/pull/952) Use C preprocessor to properly hide trampoline functions on Windows and non-x86_64 targets. From 0775d496d3dfa9df6c078c17a9b97b682e23b487 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 12 Nov 2019 15:12:31 +0100 Subject: [PATCH 122/342] feat(runtime-core) Replace the `field-offset` crate by a custom `offset_of!` macro. The `field-offset` crate is unmaintained. When using its `offset_of!` macro on a struct with a field of type `std::ptr::NonNull`, in release mode, it generates a sigill. This patch removes the `field-offset` crate, and implements a custom `offset_of!` macro. --- Cargo.lock | 7 --- lib/runtime-core/Cargo.toml | 3 - lib/runtime-core/src/lib.rs | 4 -- lib/runtime-core/src/vm.rs | 114 ++++++++++++++++++++++++++---------- 4 files changed, 83 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0720c9eebbd..52ff96ffcbb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -417,11 +417,6 @@ dependencies = [ "synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "field-offset" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -1529,7 +1524,6 @@ dependencies = [ "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)", "hex 0.3.2 (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)", @@ -1714,7 +1708,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" "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" "checksum generational-arena 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fd04ad33021a0409d3f1afbfb89d9f02c10caee73c28f5ac197474dd53e7cf7c" diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml index 0acbe718ede..ba40447fbe9 100644 --- a/lib/runtime-core/Cargo.toml +++ b/lib/runtime-core/Cargo.toml @@ -42,9 +42,6 @@ version = "0.8" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["memoryapi"] } -[dev-dependencies] -field-offset = "0.1" - [build-dependencies] blake2b_simd = "0.5" rustc_version = "0.2" diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index d8b558ebc07..eb506f4cb43 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -26,10 +26,6 @@ #![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")] #![doc(html_logo_url = "https://avatars3.githubusercontent.com/u/44205449?s=200&v=4")] -#[cfg(test)] -#[macro_use] -extern crate field_offset; - #[macro_use] extern crate serde_derive; diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index 0584633dac8..b432dcd9a4b 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -711,78 +711,136 @@ impl Anyfunc { mod vm_offset_tests { use super::{Anyfunc, Ctx, ImportedFunc, InternalCtx, LocalGlobal, LocalMemory, LocalTable}; + // Inspired by https://internals.rust-lang.org/t/discussion-on-offset-of/7440/2. + macro_rules! offset_of { + ($struct:path, $field:ident) => {{ + fn offset() -> usize { + use std::mem; + + let structure = mem::MaybeUninit::<$struct>::uninit(); + + let &$struct { + $field: ref field, .. + } = unsafe { &*structure.as_ptr() }; + + let offset = + (field as *const _ as usize).wrapping_sub(&structure as *const _ as usize); + + assert!((0..=mem::size_of_val(&structure)).contains(&offset)); + + offset + } + + offset() + }}; + } + + #[test] + fn offset_of() { + use std::{mem, ptr::NonNull}; + + struct S0; + + #[repr(C)] + struct S1 { + f1: u8, + f2: u16, + f3: u32, + f4: u64, + f5: u128, + f6: f32, + f7: f64, + f8: NonNull, + f9: Option>, + f10: *mut S0, + z: u8, + } + + assert_eq!(offset_of!(S1, f1), 0); + assert_eq!(offset_of!(S1, f2), 2); + assert_eq!(offset_of!(S1, f3), 4); + assert_eq!(offset_of!(S1, f4), 8); + assert_eq!(offset_of!(S1, f5), 16); + assert_eq!(offset_of!(S1, f6), 32); + assert_eq!(offset_of!(S1, f7), 40); + assert_eq!(offset_of!(S1, f8), 40 + mem::size_of::()); + assert_eq!(offset_of!(S1, f9), 48 + mem::size_of::()); + assert_eq!(offset_of!(S1, f10), 56 + mem::size_of::()); + assert_eq!(offset_of!(S1, z), 64 + mem::size_of::()); + } + #[test] fn vmctx() { - assert_eq!(0usize, offset_of!(Ctx => internal).get_byte_offset(),); + assert_eq!(0usize, offset_of!(Ctx, internal)); assert_eq!( Ctx::offset_memories() as usize, - offset_of!(InternalCtx => memories).get_byte_offset(), + offset_of!(InternalCtx, memories), ); assert_eq!( Ctx::offset_tables() as usize, - offset_of!(InternalCtx => tables).get_byte_offset(), + offset_of!(InternalCtx, tables), ); assert_eq!( Ctx::offset_globals() as usize, - offset_of!(InternalCtx => globals).get_byte_offset(), + offset_of!(InternalCtx, globals), ); assert_eq!( Ctx::offset_imported_memories() as usize, - offset_of!(InternalCtx => imported_memories).get_byte_offset(), + offset_of!(InternalCtx, imported_memories), ); assert_eq!( Ctx::offset_imported_tables() as usize, - offset_of!(InternalCtx => imported_tables).get_byte_offset(), + offset_of!(InternalCtx, imported_tables), ); assert_eq!( Ctx::offset_imported_globals() as usize, - offset_of!(InternalCtx => imported_globals).get_byte_offset(), + offset_of!(InternalCtx, imported_globals), ); assert_eq!( Ctx::offset_imported_funcs() as usize, - offset_of!(InternalCtx => imported_funcs).get_byte_offset(), + offset_of!(InternalCtx, imported_funcs), ); assert_eq!( Ctx::offset_intrinsics() as usize, - offset_of!(InternalCtx => intrinsics).get_byte_offset(), + offset_of!(InternalCtx, intrinsics), ); assert_eq!( Ctx::offset_stack_lower_bound() as usize, - offset_of!(InternalCtx => stack_lower_bound).get_byte_offset(), + offset_of!(InternalCtx, stack_lower_bound), ); assert_eq!( Ctx::offset_memory_base() as usize, - offset_of!(InternalCtx => memory_base).get_byte_offset(), + offset_of!(InternalCtx, memory_base), ); assert_eq!( Ctx::offset_memory_bound() as usize, - offset_of!(InternalCtx => memory_bound).get_byte_offset(), + offset_of!(InternalCtx, memory_bound), ); assert_eq!( Ctx::offset_internals() as usize, - offset_of!(InternalCtx => internals).get_byte_offset(), + offset_of!(InternalCtx, internals), ); assert_eq!( Ctx::offset_interrupt_signal_mem() as usize, - offset_of!(InternalCtx => interrupt_signal_mem).get_byte_offset(), + offset_of!(InternalCtx, interrupt_signal_mem), ); assert_eq!( Ctx::offset_local_functions() as usize, - offset_of!(Ctx => local_functions).get_byte_offset(), + offset_of!(Ctx, local_functions), ); } @@ -790,12 +848,12 @@ mod vm_offset_tests { fn imported_func() { assert_eq!( ImportedFunc::offset_func() as usize, - offset_of!(ImportedFunc => func).get_byte_offset(), + offset_of!(ImportedFunc, func), ); assert_eq!( ImportedFunc::offset_vmctx() as usize, - offset_of!(ImportedFunc => vmctx).get_byte_offset(), + offset_of!(ImportedFunc, vmctx), ); } @@ -803,12 +861,12 @@ mod vm_offset_tests { fn local_table() { assert_eq!( LocalTable::offset_base() as usize, - offset_of!(LocalTable => base).get_byte_offset(), + offset_of!(LocalTable, base), ); assert_eq!( LocalTable::offset_count() as usize, - offset_of!(LocalTable => count).get_byte_offset(), + offset_of!(LocalTable, count), ); } @@ -816,12 +874,12 @@ mod vm_offset_tests { fn local_memory() { assert_eq!( LocalMemory::offset_base() as usize, - offset_of!(LocalMemory => base).get_byte_offset(), + offset_of!(LocalMemory, base), ); assert_eq!( LocalMemory::offset_bound() as usize, - offset_of!(LocalMemory => bound).get_byte_offset(), + offset_of!(LocalMemory, bound), ); } @@ -829,25 +887,19 @@ mod vm_offset_tests { fn local_global() { assert_eq!( LocalGlobal::offset_data() as usize, - offset_of!(LocalGlobal => data).get_byte_offset(), + offset_of!(LocalGlobal, data), ); } #[test] fn cc_anyfunc() { - assert_eq!( - Anyfunc::offset_func() as usize, - offset_of!(Anyfunc => func).get_byte_offset(), - ); + assert_eq!(Anyfunc::offset_func() as usize, offset_of!(Anyfunc, func),); - assert_eq!( - Anyfunc::offset_vmctx() as usize, - offset_of!(Anyfunc => ctx).get_byte_offset(), - ); + assert_eq!(Anyfunc::offset_vmctx() as usize, offset_of!(Anyfunc, ctx),); assert_eq!( Anyfunc::offset_sig_id() as usize, - offset_of!(Anyfunc => sig_id).get_byte_offset(), + offset_of!(Anyfunc, sig_id), ); } } From a1e8a8f0dbc0645a9cb017b31b778c3a61f91fe5 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 12 Nov 2019 15:17:36 +0100 Subject: [PATCH 123/342] fix(runtime-core) Same bug with `field-offset` as before. It will be fixed in a following PR. --- lib/runtime-core/src/vm.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index 7dfb7de2ba2..94d89df2e92 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -838,15 +838,9 @@ mod vm_offset_tests { #[test] fn imported_func() { - assert_eq!( - ImportedFunc::offset_func() as usize, - offset_of!(ImportedFunc => func).get_byte_offset(), - ); + assert_eq!(ImportedFunc::offset_func() as usize, 0); - assert_eq!( - ImportedFunc::offset_func_ctx() as usize, - offset_of!(ImportedFunc => func_ctx).get_byte_offset(), - ); + assert_eq!(ImportedFunc::offset_func_ctx() as usize, 8); } #[test] From f1339b4033e2da2ffb400dbcff3ae0920a91fe9f Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 13 Nov 2019 01:00:27 +0800 Subject: [PATCH 124/342] Fix known_registers size. --- lib/runtime-core/src/fault.rs | 2 +- lib/runtime-core/src/state.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index 6471ec952c0..9a7cf39e40c 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -476,7 +476,7 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> F let ucontext = ucontext as *mut ucontext; let gregs = &(*ucontext).uc_mcontext.regs; - 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[15] as _); known_registers[X64Register::GPR(GPR::R14).to_index().0] = Some(gregs[14] as _); diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index f48548514e0..35052b0fae2 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -529,7 +529,7 @@ pub mod x64 { let mut last_stack_offset: u64 = 0; // rbp - let mut known_registers: [Option; 24] = [None; 24]; + let mut known_registers: [Option; 32] = [None; 32]; let local_functions_vec: Vec<&FunctionStateMap> = msm.local_functions.iter().map(|(_, v)| v).collect(); From f1e5cd39d8cb1c1e348f816703dac04c1450c92d Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 12 Nov 2019 12:54:28 -0800 Subject: [PATCH 125/342] Add support for new WASI snapshot, backwards compat too --- Cargo.lock | 1 - lib/wasi/Cargo.toml | 5 + lib/wasi/src/lib.rs | 87 ++++++++++- lib/wasi/src/syscalls/legacy/mod.rs | 6 + lib/wasi/src/syscalls/legacy/snapshot0.rs | 178 ++++++++++++++++++++++ lib/wasi/src/syscalls/mod.rs | 3 + lib/wasi/src/syscalls/types.rs | 66 +++++++- lib/wasi/src/utils.rs | 41 +++-- src/bin/wasmer.rs | 49 +++--- 9 files changed, 397 insertions(+), 39 deletions(-) create mode 100644 lib/wasi/src/syscalls/legacy/mod.rs create mode 100644 lib/wasi/src/syscalls/legacy/snapshot0.rs diff --git a/Cargo.lock b/Cargo.lock index 0720c9eebbd..705efb20bbc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1504,7 +1504,6 @@ dependencies = [ "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.10.1", - "wasmer-llvm-backend 0.10.1", "wasmer-runtime-core 0.10.1", "wasmer-singlepass-backend 0.10.1", ] diff --git a/lib/wasi/Cargo.toml b/lib/wasi/Cargo.toml index 8a85acc2d07..e413c313e69 100644 --- a/lib/wasi/Cargo.toml +++ b/lib/wasi/Cargo.toml @@ -21,3 +21,8 @@ wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } [target.'cfg(windows)'.dependencies] winapi = "0.3" + +[features] +# Enable support for the older snapshot0 WASI modules +snapshot0 = [] +default = ["snapshot0"] \ No newline at end of file diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index 978517c7c44..a40987b2b19 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -37,7 +37,7 @@ use self::syscalls::*; use std::ffi::c_void; use std::path::PathBuf; -pub use self::utils::is_wasi_module; +pub use self::utils::{get_wasi_version, is_wasi_module, WasiVersion}; use wasmer_runtime_core::{func, import::ImportObject, imports}; @@ -79,7 +79,7 @@ pub fn generate_import_object( imports! { // This generates the wasi state. state_gen, - "wasi_unstable" => { + "wasi_snapshot_preview1" => { "args_get" => func!(args_get), "args_sizes_get" => func!(args_sizes_get), "clock_res_get" => func!(clock_res_get), @@ -128,3 +128,86 @@ pub fn generate_import_object( }, } } + +#[cfg(feature = "snapshot0")] +/// Creates a Wasi [`ImportObject`] with [`WasiState`]. +pub fn generate_import_object_snapshot0( + args: Vec>, + envs: Vec>, + preopened_files: Vec, + mapped_dirs: Vec<(String, PathBuf)>, +) -> ImportObject { + let state_gen = move || { + // TODO: look into removing all these unnecessary clones + fn state_destructor(data: *mut c_void) { + unsafe { + drop(Box::from_raw(data as *mut WasiState)); + } + } + let preopened_files = preopened_files.clone(); + let mapped_dirs = mapped_dirs.clone(); + //let wasi_builder = create_wasi_instance(); + + let state = Box::new(WasiState { + fs: WasiFs::new(&preopened_files, &mapped_dirs).expect("Could not create WASI FS"), + args: args.clone(), + envs: envs.clone(), + }); + + ( + Box::into_raw(state) as *mut c_void, + state_destructor as fn(*mut c_void), + ) + }; + imports! { + // This generates the wasi state. + state_gen, + "wasi_unstable" => { + "args_get" => func!(args_get), + "args_sizes_get" => func!(args_sizes_get), + "clock_res_get" => func!(clock_res_get), + "clock_time_get" => func!(clock_time_get), + "environ_get" => func!(environ_get), + "environ_sizes_get" => func!(environ_sizes_get), + "fd_advise" => func!(fd_advise), + "fd_allocate" => func!(fd_allocate), + "fd_close" => func!(fd_close), + "fd_datasync" => func!(fd_datasync), + "fd_fdstat_get" => func!(fd_fdstat_get), + "fd_fdstat_set_flags" => func!(fd_fdstat_set_flags), + "fd_fdstat_set_rights" => func!(fd_fdstat_set_rights), + "fd_filestat_get" => func!(legacy::snapshot0::fd_filestat_get), + "fd_filestat_set_size" => func!(fd_filestat_set_size), + "fd_filestat_set_times" => func!(fd_filestat_set_times), + "fd_pread" => func!(fd_pread), + "fd_prestat_get" => func!(fd_prestat_get), + "fd_prestat_dir_name" => func!(fd_prestat_dir_name), + "fd_pwrite" => func!(fd_pwrite), + "fd_read" => func!(fd_read), + "fd_readdir" => func!(fd_readdir), + "fd_renumber" => func!(fd_renumber), + "fd_seek" => func!(legacy::snapshot0::fd_seek), + "fd_sync" => func!(fd_sync), + "fd_tell" => func!(fd_tell), + "fd_write" => func!(fd_write), + "path_create_directory" => func!(path_create_directory), + "path_filestat_get" => func!(legacy::snapshot0::path_filestat_get), + "path_filestat_set_times" => func!(path_filestat_set_times), + "path_link" => func!(path_link), + "path_open" => func!(path_open), + "path_readlink" => func!(path_readlink), + "path_remove_directory" => func!(path_remove_directory), + "path_rename" => func!(path_rename), + "path_symlink" => func!(path_symlink), + "path_unlink_file" => func!(path_unlink_file), + "poll_oneoff" => func!(legacy::snapshot0::poll_oneoff), + "proc_exit" => func!(proc_exit), + "proc_raise" => func!(proc_raise), + "random_get" => func!(random_get), + "sched_yield" => func!(sched_yield), + "sock_recv" => func!(sock_recv), + "sock_send" => func!(sock_send), + "sock_shutdown" => func!(sock_shutdown), + }, + } +} diff --git a/lib/wasi/src/syscalls/legacy/mod.rs b/lib/wasi/src/syscalls/legacy/mod.rs new file mode 100644 index 00000000000..94e713b2300 --- /dev/null +++ b/lib/wasi/src/syscalls/legacy/mod.rs @@ -0,0 +1,6 @@ +//! These modules provide wrappers and implementations for older version of WASI. +//! +//! If you are relying on legacy WASI, please upgrade for the best experience. + +#[cfg(feature = "snapshot0")] +pub mod snapshot0; diff --git a/lib/wasi/src/syscalls/legacy/snapshot0.rs b/lib/wasi/src/syscalls/legacy/snapshot0.rs new file mode 100644 index 00000000000..38a1811146b --- /dev/null +++ b/lib/wasi/src/syscalls/legacy/snapshot0.rs @@ -0,0 +1,178 @@ +use crate::ptr::{Array, WasmPtr}; +use crate::syscalls; +use crate::syscalls::types::{self, snapshot0}; +use wasmer_runtime_core::vm::Ctx; + +/// Wrapper around `syscalls::fd_filestat_get` with extra logic to handle the size +/// difference of `wasi_filestat_t` +/// +/// WARNING: this function involves saving, clobbering, and restoring unrelated +/// Wasm memory. If the memory clobbered by the current syscall is also used by +/// that syscall, then it may break. +pub fn fd_filestat_get( + ctx: &mut Ctx, + fd: types::__wasi_fd_t, + buf: WasmPtr, +) -> types::__wasi_errno_t { + let memory = ctx.memory(0); + + // transmute the WasmPtr into a WasmPtr where T2 > T1, this will read extra memory. + // The edge case of this causing an OOB is not handled, if the new field is OOB, then the entire + // memory access will fail. + let new_buf: WasmPtr = unsafe { std::mem::transmute(buf) }; + + // Copy the data including the extra data + let new_filestat_setup: types::__wasi_filestat_t = + wasi_try!(new_buf.deref(memory)).get().clone(); + + // Set up complete, make the call with the pointer that will write to the + // struct and some unrelated memory after the struct. + let result = syscalls::fd_filestat_get(ctx, fd, new_buf); + + // reborrow memory + let memory = ctx.memory(0); + + // get the values written to memory + let new_filestat = wasi_try!(new_buf.deref(memory)).get(); + // translate the new struct into the old struct in host memory + let old_stat = snapshot0::__wasi_filestat_t { + st_dev: new_filestat.st_dev, + st_ino: new_filestat.st_ino, + st_filetype: new_filestat.st_filetype, + st_nlink: new_filestat.st_nlink as u32, + st_size: new_filestat.st_size, + st_atim: new_filestat.st_atim, + st_mtim: new_filestat.st_mtim, + st_ctim: new_filestat.st_ctim, + }; + + // write back the original values at the pointer's memory locations + // (including the memory unrelated to the pointer) + wasi_try!(new_buf.deref(memory)).set(new_filestat_setup); + + // Now that this memory is back as it was, write the translated filestat + // into memory leaving it as it should be + wasi_try!(buf.deref(memory)).set(old_stat); + + result +} + +/// Wrapper around `syscalls::path_filestat_get` with extra logic to handle the size +/// difference of `wasi_filestat_t` +pub fn path_filestat_get( + ctx: &mut Ctx, + fd: types::__wasi_fd_t, + flags: types::__wasi_lookupflags_t, + path: WasmPtr, + path_len: u32, + buf: WasmPtr, +) -> types::__wasi_errno_t { + // see `fd_filestat_get` in this file for an explanation of this strange behavior + let memory = ctx.memory(0); + + let new_buf: WasmPtr = unsafe { std::mem::transmute(buf) }; + let new_filestat_setup: types::__wasi_filestat_t = + wasi_try!(new_buf.deref(memory)).get().clone(); + + let result = syscalls::path_filestat_get(ctx, fd, flags, path, path_len, new_buf); + + let memory = ctx.memory(0); + let new_filestat = wasi_try!(new_buf.deref(memory)).get(); + let old_stat = snapshot0::__wasi_filestat_t { + st_dev: new_filestat.st_dev, + st_ino: new_filestat.st_ino, + st_filetype: new_filestat.st_filetype, + st_nlink: new_filestat.st_nlink as u32, + st_size: new_filestat.st_size, + st_atim: new_filestat.st_atim, + st_mtim: new_filestat.st_mtim, + st_ctim: new_filestat.st_ctim, + }; + + wasi_try!(new_buf.deref(memory)).set(new_filestat_setup); + wasi_try!(buf.deref(memory)).set(old_stat); + + result +} + +/// Wrapper around `syscalls::fd_seek` with extra logic to remap the values +/// of `__wasi_whence_t` +pub fn fd_seek( + ctx: &mut Ctx, + fd: types::__wasi_fd_t, + offset: types::__wasi_filedelta_t, + whence: snapshot0::__wasi_whence_t, + newoffset: WasmPtr, +) -> types::__wasi_errno_t { + let new_whence = match whence { + snapshot0::__WASI_WHENCE_CUR => types::__WASI_WHENCE_CUR, + snapshot0::__WASI_WHENCE_END => types::__WASI_WHENCE_END, + snapshot0::__WASI_WHENCE_SET => types::__WASI_WHENCE_SET, + // if it's invalid, let the new fd_seek handle it + _ => whence, + }; + syscalls::fd_seek(ctx, fd, offset, new_whence, newoffset) +} + +/// Wrapper around `syscalls::poll_oneoff` with extra logic to add the removed +/// userdata field back +pub fn poll_oneoff( + ctx: &mut Ctx, + in_: WasmPtr, + out_: WasmPtr, + nsubscriptions: u32, + nevents: WasmPtr, +) -> types::__wasi_errno_t { + // in this case the new type is smaller than the old type, so it all fits into memory, + // we just need to readjust and copy it + + // we start by adjusting `in_` into a format that the new code can understand + let memory = ctx.memory(0); + let mut in_origs: Vec = vec![]; + for in_sub in wasi_try!(in_.deref(memory, 0, nsubscriptions)) { + in_origs.push(in_sub.get().clone()); + } + + // get a pointer to the smaller new type + let in_new_type_ptr: WasmPtr = + unsafe { std::mem::transmute(in_) }; + + for (in_sub_new, orig) in wasi_try!(in_new_type_ptr.deref(memory, 0, nsubscriptions)) + .iter() + .zip(in_origs.iter()) + { + in_sub_new.set(types::__wasi_subscription_t { + userdata: orig.userdata, + type_: orig.type_, + u: if orig.type_ == types::__WASI_EVENTTYPE_CLOCK { + types::__wasi_subscription_u { + clock: types::__wasi_subscription_clock_t { + clock_id: unsafe { orig.u.clock.clock_id }, + timeout: unsafe { orig.u.clock.timeout }, + precision: unsafe { orig.u.clock.precision }, + flags: unsafe { orig.u.clock.flags }, + }, + } + } else { + types::__wasi_subscription_u { + fd_readwrite: unsafe { orig.u.fd_readwrite }, + } + }, + }); + } + + // make the call + let result = syscalls::poll_oneoff(ctx, in_new_type_ptr, out_, nsubscriptions, nevents); + + // replace the old values of in, in case the calling code reuses the memory + let memory = ctx.memory(0); + + for (in_sub, orig) in wasi_try!(in_.deref(memory, 0, nsubscriptions)) + .iter() + .zip(in_origs.into_iter()) + { + in_sub.set(orig); + } + + result +} diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index 3db7323e7c9..3cf8d22b7fa 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -5,6 +5,9 @@ pub mod unix; #[cfg(any(target_os = "windows"))] pub mod windows; +#[cfg(any(feature = "snapshot0"))] +pub mod legacy; + use self::types::*; use crate::{ ptr::{Array, WasmPtr}, diff --git a/lib/wasi/src/syscalls/types.rs b/lib/wasi/src/syscalls/types.rs index 060f3cd435c..6e4444ee933 100644 --- a/lib/wasi/src/syscalls/types.rs +++ b/lib/wasi/src/syscalls/types.rs @@ -416,7 +416,7 @@ pub struct __wasi_iovec_t { unsafe impl ValueType for __wasi_iovec_t {} -pub type __wasi_linkcount_t = u32; +pub type __wasi_linkcount_t = u64; pub type __wasi_lookupflags_t = u32; pub const __WASI_LOOKUP_SYMLINK_FOLLOW: u32 = 1 << 0; @@ -559,7 +559,6 @@ pub const __WASI_SUBSCRIPTION_CLOCK_ABSTIME: u16 = 1 << 0; #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[repr(C)] pub struct __wasi_subscription_clock_t { - pub userdata: __wasi_userdata_t, pub clock_id: __wasi_clockid_t, pub timeout: __wasi_timestamp_t, pub precision: __wasi_timestamp_t, @@ -575,8 +574,8 @@ pub struct __wasi_subscription_fs_readwrite_t { #[derive(Copy, Clone)] #[repr(C)] pub union __wasi_subscription_u { - clock: __wasi_subscription_clock_t, - fd_readwrite: __wasi_subscription_fs_readwrite_t, + pub clock: __wasi_subscription_clock_t, + pub fd_readwrite: __wasi_subscription_fs_readwrite_t, } #[derive(Copy, Clone)] @@ -698,6 +697,59 @@ pub type __wasi_timestamp_t = u64; pub type __wasi_userdata_t = u64; pub type __wasi_whence_t = u8; -pub const __WASI_WHENCE_CUR: u8 = 0; -pub const __WASI_WHENCE_END: u8 = 1; -pub const __WASI_WHENCE_SET: u8 = 2; +pub const __WASI_WHENCE_SET: u8 = 0; +pub const __WASI_WHENCE_CUR: u8 = 1; +pub const __WASI_WHENCE_END: u8 = 2; + +pub mod snapshot0 { + use serde::{Deserialize, Serialize}; + pub type __wasi_linkcount_t = u32; + use wasmer_runtime_core::types::ValueType; + + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + #[repr(C)] + pub struct __wasi_subscription_clock_t { + pub userdata: super::__wasi_userdata_t, + pub clock_id: super::__wasi_clockid_t, + pub timeout: super::__wasi_timestamp_t, + pub precision: super::__wasi_timestamp_t, + pub flags: super::__wasi_subclockflags_t, + } + + #[derive(Copy, Clone)] + #[repr(C)] + pub union __wasi_subscription_u { + pub clock: __wasi_subscription_clock_t, + pub fd_readwrite: super::__wasi_subscription_fs_readwrite_t, + } + + #[derive(Copy, Clone)] + #[repr(C)] + pub struct __wasi_subscription_t { + pub userdata: super::__wasi_userdata_t, + pub type_: super::__wasi_eventtype_t, + pub u: __wasi_subscription_u, + } + + unsafe impl ValueType for __wasi_subscription_t {} + + pub type __wasi_whence_t = u8; + pub const __WASI_WHENCE_CUR: u8 = 0; + pub const __WASI_WHENCE_END: u8 = 1; + pub const __WASI_WHENCE_SET: u8 = 2; + + #[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] + #[repr(C)] + pub struct __wasi_filestat_t { + pub st_dev: super::__wasi_device_t, + pub st_ino: super::__wasi_inode_t, + pub st_filetype: super::__wasi_filetype_t, + pub st_nlink: __wasi_linkcount_t, + pub st_size: super::__wasi_filesize_t, + pub st_atim: super::__wasi_timestamp_t, + pub st_mtim: super::__wasi_timestamp_t, + pub st_ctim: super::__wasi_timestamp_t, + } + + unsafe impl ValueType for __wasi_filestat_t {} +} diff --git a/lib/wasi/src/utils.rs b/lib/wasi/src/utils.rs index f96e35958df..bb0a554f8e5 100644 --- a/lib/wasi/src/utils.rs +++ b/lib/wasi/src/utils.rs @@ -1,18 +1,37 @@ use wasmer_runtime_core::module::Module; +#[allow(dead_code)] /// Check if a provided module is compiled with WASI support pub fn is_wasi_module(module: &Module) -> bool { - if module.info().imported_functions.is_empty() { - return false; - } - for (_, import_name) in &module.info().imported_functions { - let namespace = module - .info() - .namespace_table - .get(import_name.namespace_index); - if namespace != "wasi_unstable" { - return false; + get_wasi_version(module) == Some(WasiVersion::Snapshot1) +} + +/// The version of WASI. This is determined by the namespace string +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum WasiVersion { + /// "wasi_unstable" + Snapshot0, + /// "wasi_snapshot_preview1" + Snapshot1, +} + +pub fn get_wasi_version(module: &Module) -> Option { + let mut import_iter = module + .info() + .imported_functions + .iter() + .map(|(_, import_name)| import_name.namespace_index); + + // returns None if empty + let first = import_iter.next()?; + if import_iter.all(|idx| idx == first) { + match module.info().namespace_table.get(first) { + "wasi_unstable" => Some(WasiVersion::Snapshot0), + "wasi_snapshot_preview1" => Some(WasiVersion::Snapshot1), + _ => None, } + } else { + // not all funcs have the same namespace: therefore it's not WASI + None } - true } diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 6195e60a612..ff8cc884136 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -582,25 +582,38 @@ fn execute_wasm(options: &Run) -> Result<(), String> { ) .map_err(|e| format!("{:?}", e))?; } else { - if cfg!(feature = "wasi") && wasmer_wasi::is_wasi_module(&module) { - let import_object = wasmer_wasi::generate_import_object( - if let Some(cn) = &options.command_name { - [cn.clone()] - } else { - [options.path.to_str().unwrap().to_owned()] + let wasi_version = wasmer_wasi::get_wasi_version(&module); + if cfg!(feature = "wasi") && wasi_version.is_some() { + let wasi_version = wasi_version.unwrap(); + let args = if let Some(cn) = &options.command_name { + [cn.clone()] + } else { + [options.path.to_str().unwrap().to_owned()] + } + .iter() + .chain(options.args.iter()) + .cloned() + .map(|arg| arg.into_bytes()) + .collect(); + let envs = env_vars + .into_iter() + .map(|(k, v)| format!("{}={}", k, v).into_bytes()) + .collect(); + let preopened_files = options.pre_opened_directories.clone(); + + let import_object = match wasi_version { + wasmer_wasi::WasiVersion::Snapshot0 => { + wasmer_wasi::generate_import_object_snapshot0( + args, + envs, + preopened_files, + mapped_dirs, + ) + } + wasmer_wasi::WasiVersion::Snapshot1 => { + wasmer_wasi::generate_import_object(args, envs, preopened_files, mapped_dirs) } - .iter() - .chain(options.args.iter()) - .cloned() - .map(|arg| arg.into_bytes()) - .collect(), - env_vars - .into_iter() - .map(|(k, v)| format!("{}={}", k, v).into_bytes()) - .collect(), - options.pre_opened_directories.clone(), - mapped_dirs, - ); + }; #[allow(unused_mut)] // mut used in feature let mut instance = module From 2b2a0628f7b21263a2f049a358a9211502ef243f Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 12 Nov 2019 17:02:07 -0800 Subject: [PATCH 126/342] Update from feedback, improve docs on new wasi fns --- CHANGELOG.md | 2 ++ Cargo.lock | 1 + lib/wasi/src/lib.rs | 7 ++++--- lib/wasi/src/utils.rs | 10 +++++++--- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9efec44fdb4..becd75e7838 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## **[Unreleased]** +- [#957](https://github.com/wasmerio/wasmer/pull/957) Change the meaning of `wasmer_wasi::is_wasi_module` to detect any type of WASI module, add support for new wasi snapshot_preview1 + ## 0.10.0 - 2019-11-11 - [#952](https://github.com/wasmerio/wasmer/pull/952) Use C preprocessor to properly hide trampoline functions on Windows and non-x86_64 targets. diff --git a/Cargo.lock b/Cargo.lock index 705efb20bbc..0720c9eebbd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1504,6 +1504,7 @@ dependencies = [ "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.10.1", + "wasmer-llvm-backend 0.10.1", "wasmer-runtime-core 0.10.1", "wasmer-singlepass-backend 0.10.1", ] diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index a40987b2b19..c0bb562de1e 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -12,7 +12,7 @@ //! Wasmer's WASI implementation //! -//! Use `generate_import_object` to create an `ImportObject`. This `ImportObject` +//! Use `generate_import_object` to create an [`ImportObject`]. This [`ImportObject`] //! can be combined with a module to create an `Instance` which can execute WASI //! Wasm functions. //! @@ -47,7 +47,8 @@ pub struct ExitCode { pub code: syscalls::types::__wasi_exitcode_t, } -/// Creates a Wasi [`ImportObject`] with [`WasiState`]. +/// Creates a Wasi [`ImportObject`] with [`WasiState`] with the latest snapshot +/// of WASI. pub fn generate_import_object( args: Vec>, envs: Vec>, @@ -130,7 +131,7 @@ pub fn generate_import_object( } #[cfg(feature = "snapshot0")] -/// Creates a Wasi [`ImportObject`] with [`WasiState`]. +/// Creates a legacy Wasi [`ImportObject`] with [`WasiState`]. pub fn generate_import_object_snapshot0( args: Vec>, envs: Vec>, diff --git a/lib/wasi/src/utils.rs b/lib/wasi/src/utils.rs index bb0a554f8e5..b19a404884b 100644 --- a/lib/wasi/src/utils.rs +++ b/lib/wasi/src/utils.rs @@ -1,9 +1,10 @@ use wasmer_runtime_core::module::Module; #[allow(dead_code)] -/// Check if a provided module is compiled with WASI support +/// Check if a provided module is compiled for some version of WASI. +/// Use [`get_wasi_version`] to find out which version of WASI the module is. pub fn is_wasi_module(module: &Module) -> bool { - get_wasi_version(module) == Some(WasiVersion::Snapshot1) + get_wasi_version(module).is_some() } /// The version of WASI. This is determined by the namespace string @@ -15,6 +16,7 @@ pub enum WasiVersion { Snapshot1, } +/// Detect the version of WASI being used from the namespace pub fn get_wasi_version(module: &Module) -> Option { let mut import_iter = module .info() @@ -25,13 +27,15 @@ pub fn get_wasi_version(module: &Module) -> Option { // returns None if empty let first = import_iter.next()?; if import_iter.all(|idx| idx == first) { + // once we know that all the namespaces are the same, we can use it to + // detect which version of WASI this is match module.info().namespace_table.get(first) { "wasi_unstable" => Some(WasiVersion::Snapshot0), "wasi_snapshot_preview1" => Some(WasiVersion::Snapshot1), _ => None, } } else { - // not all funcs have the same namespace: therefore it's not WASI + // not all funcs have the same namespace, therefore it's not WASI None } } From c552514fd2b2503bda3e0c317be40d5031dd07c8 Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 13 Nov 2019 11:35:44 +0800 Subject: [PATCH 127/342] Disable NaN canonicalizing on aarch64. --- lib/singlepass-backend/src/codegen_x64.rs | 800 +++++++++--------- lib/singlepass-backend/src/emitter_x64.rs | 2 + .../src/translator_aarch64.rs | 2 + 3 files changed, 422 insertions(+), 382 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index e42a66fc1c7..018a3480133 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -3108,209 +3108,227 @@ impl FunctionCodeGenerator for X64FunctionCode { Assembler::emit_vdivss, ), 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); + if !a.arch_supports_canonicalize_nan() { + Self::emit_fp_binop_avx( + a, + &mut self.machine, + &mut self.value_stack, + Assembler::emit_vmaxss, + ); + } else { + 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 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 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); + 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!(), } - _ => 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); + 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()); - 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); + if !a.arch_supports_canonicalize_nan() { + Self::emit_fp_binop_avx( + a, + &mut self.machine, + &mut self.value_stack, + Assembler::emit_vminss, + ); + } else { + 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 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 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; - 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_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(tmpg1), - ); - a.emit_mov( - Size::S64, - Location::Memory(tmpg1, 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(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); + 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(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(); + 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(tmpg1), + ); + a.emit_mov( + Size::S64, + Location::Memory(tmpg1, 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(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!(), } - _ => 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); + 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::F32Eq => Self::emit_fp_cmpop_avx( a, @@ -3502,209 +3520,227 @@ impl FunctionCodeGenerator for X64FunctionCode { Assembler::emit_vdivsd, ), 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); + if !a.arch_supports_canonicalize_nan() { + Self::emit_fp_binop_avx( + a, + &mut self.machine, + &mut self.value_stack, + Assembler::emit_vmaxsd, + ); + } else { + 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 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 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); + 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!(), } - _ => 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); + 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); + if !a.arch_supports_canonicalize_nan() { + Self::emit_fp_binop_avx( + a, + &mut self.machine, + &mut self.value_stack, + Assembler::emit_vminsd, + ); + } else { + 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 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 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); + 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!(), } - _ => 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); + 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, diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index b44fb11f60a..db819b19c3a 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -267,6 +267,8 @@ pub trait Emitter { fn arch_emit_tzcnt(&mut self, _sz: Size, _src: Location, _dst: Location) { unimplemented!() } + + fn arch_supports_canonicalize_nan(&self) -> bool { true } } fn _dummy(a: &mut Assembler) { diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 35d4fe85a08..f5fd5c228d2 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -1709,6 +1709,8 @@ impl Emitter for Assembler { ; .dword (ty as u8 as i32) ); } + + fn arch_supports_canonicalize_nan(&self) -> bool { false } } fn emit_clz_variant( From 47f1e2a4efafa289d2474bc1f1b5a04aa73d7b82 Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 13 Nov 2019 14:18:21 +0800 Subject: [PATCH 128/342] Fix parameter loading. --- lib/singlepass-backend/src/codegen_x64.rs | 47 ++++++++++++++++++++--- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 018a3480133..3014c7aa8be 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -163,15 +163,52 @@ lazy_static! { ; ldr x9, >v_65536 ; sub sp, sp, x9 // Pre-allocate the WASM stack - // return address - ; adr x9, >done - ; sub x28, x28, 8 - ; str x9, [x28] // Keep this consistent with RSP mapping in translator_aarch64 + ; mov x19, x0 // stack_top + ; mov x20, x1 // stack_base // ctx ; mov X(crate::translator_aarch64::map_gpr(GPR::RDI).x()), x2 - // TODO: params + // params + ; cmp x20, x19 + ; b.eq >end_copy_params + ; sub x20, x20, 8 + ; ldr X(crate::translator_aarch64::map_gpr(GPR::RSI).x()), [x20] + + ; cmp x20, x19 + ; b.eq >end_copy_params + ; sub x20, x20, 8 + ; ldr X(crate::translator_aarch64::map_gpr(GPR::RDX).x()), [x20] + + ; cmp x20, x19 + ; b.eq >end_copy_params + ; sub x20, x20, 8 + ; ldr X(crate::translator_aarch64::map_gpr(GPR::RCX).x()), [x20] + + ; cmp x20, x19 + ; b.eq >end_copy_params + ; sub x20, x20, 8 + ; ldr X(crate::translator_aarch64::map_gpr(GPR::R8).x()), [x20] + + ; cmp x20, x19 + ; b.eq >end_copy_params + ; sub x20, x20, 8 + ; ldr X(crate::translator_aarch64::map_gpr(GPR::R9).x()), [x20] + + ; copy_loop: + ; cmp x20, x19 + ; b.eq >end_copy_params + ; ldr x21, [x19] + ; add x19, x19, 8 + ; sub x28, x28, 8 + ; str x21, [x28] + ; b done + ; sub x28, x28, 8 + ; str x9, [x28] // Keep this consistent with RSP mapping in translator_aarch64 // Jump to target function! ; br x3 From e2956e7b1a8cff0d92d826a159362b3dfc021cb3 Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 13 Nov 2019 14:34:04 +0800 Subject: [PATCH 129/342] Run cargo fmt --- lib/singlepass-backend/src/codegen_x64.rs | 56 +++++++++++++------ lib/singlepass-backend/src/emitter_x64.rs | 4 +- .../src/translator_aarch64.rs | 4 +- 3 files changed, 46 insertions(+), 18 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 3014c7aa8be..50f21d4da92 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -3153,10 +3153,16 @@ impl FunctionCodeGenerator for X64FunctionCode { Assembler::emit_vmaxss, ); } else { - 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 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()))], @@ -3259,10 +3265,16 @@ impl FunctionCodeGenerator for X64FunctionCode { Assembler::emit_vminss, ); } else { - 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 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()))], @@ -3565,10 +3577,16 @@ impl FunctionCodeGenerator for X64FunctionCode { Assembler::emit_vmaxsd, ); } else { - 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 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()))], @@ -3671,10 +3689,16 @@ impl FunctionCodeGenerator for X64FunctionCode { Assembler::emit_vminsd, ); } else { - 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 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()))], diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index db819b19c3a..f426b6d0274 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -268,7 +268,9 @@ pub trait Emitter { unimplemented!() } - fn arch_supports_canonicalize_nan(&self) -> bool { true } + fn arch_supports_canonicalize_nan(&self) -> bool { + true + } } fn _dummy(a: &mut Assembler) { diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index f5fd5c228d2..2eedb2072d6 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -1710,7 +1710,9 @@ impl Emitter for Assembler { ); } - fn arch_supports_canonicalize_nan(&self) -> bool { false } + fn arch_supports_canonicalize_nan(&self) -> bool { + false + } } fn emit_clz_variant( From ccc474bd5d90c388d96fc0893aa1361e20d8a1f0 Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 13 Nov 2019 14:53:11 +0800 Subject: [PATCH 130/342] Remove debug files. --- address.wat | 11 ----------- br_if.wat | 32 -------------------------------- f64.wat | 22 ---------------------- fac.wat | 24 ------------------------ 4 files changed, 89 deletions(-) delete mode 100644 address.wat delete mode 100644 br_if.wat delete mode 100644 f64.wat delete mode 100644 fac.wat diff --git a/address.wat b/address.wat deleted file mode 100644 index 4abff4c8399..00000000000 --- a/address.wat +++ /dev/null @@ -1,11 +0,0 @@ -(module - (memory 1) - (data (i32.const 0) "abcdefghijklmnopqrstuvwxyz") - - (func $f_8u_good1 (param $i i32) (result i64) - (i64.load8_u offset=0 (local.get $i)) ;; 97 'a' - ) - (func $main (export "main") (result i64) - (call $f_8u_good1 (i32.const 0)) - ) -) \ No newline at end of file diff --git a/br_if.wat b/br_if.wat deleted file mode 100644 index 498196d9d7b..00000000000 --- a/br_if.wat +++ /dev/null @@ -1,32 +0,0 @@ -(module - (func $dummy) - (func $as_block_mid_value (param i32) (result i32) - (block (result i32) - (call $dummy) - (drop (br_if 0 (i32.const 20) (local.get 0))) - (return (i32.const 21)) - ) - ) - (func $nested_br_table_loop_block (param i32) (result i32) - (local.set 0 - (loop (result i32) - (block - (br_table 1 0 0 (local.get 0)) - ) - (i32.const 0) - ) - ) - (loop (result i32) - (block - (br_table 0 1 1 (local.get 0)) - ) - (i32.const 3) - ) - ) - ;; (assert_return (invoke "nested-br_table-loop-block" (i32.const 1)) (i32.const 3)) - - (func $main (export "main") (result i32) - ;; (call $as_block_mid_value (i32.const 1)) - (call $nested_br_table_loop_block (i32.const 1)) - ) -) diff --git a/f64.wat b/f64.wat deleted file mode 100644 index ba29c4258d0..00000000000 --- a/f64.wat +++ /dev/null @@ -1,22 +0,0 @@ -(module - (func $add (param $x f64) (param $y f64) (result f64) (f64.add (local.get $x) (local.get $y))) - (func $sub (param $x f64) (param $y f64) (result f64) (f64.sub (local.get $x) (local.get $y))) - (func $mul (param $x f64) (param $y f64) (result f64) (f64.mul (local.get $x) (local.get $y))) - (func $div (param $x f64) (param $y f64) (result f64) (f64.div (local.get $x) (local.get $y))) - (func $sqrt (param $x f64) (result f64) (f64.sqrt (local.get $x))) - (func $min (param $x f64) (param $y f64) (result f64) (f64.min (local.get $x) (local.get $y))) - (func $max (param $x f64) (param $y f64) (result f64) (f64.max (local.get $x) (local.get $y))) - (func (export "ceil") (param $x f64) (result f64) (f64.ceil (local.get $x))) - (func (export "floor") (param $x f64) (result f64) (f64.floor (local.get $x))) - (func (export "trunc") (param $x f64) (result f64) (f64.trunc (local.get $x))) - (func (export "nearest") (param $x f64) (result f64) (f64.nearest (local.get $x))) - (func $main (export "main") (result f64) - ;; (call $add (f64.promote_f32 (f32.const 0x1p+0)) (f64.const 0x2p+0)) ;; 3.0 - ;; (call $sub (f64.promote_f32 (f32.const 0x1p+0)) (f64.const 0x2p+0)) ;; -1.0 - ;; (call $mul (f64.promote_f32 (f32.const 0x2p+0)) (f64.const 0x3p+0)) ;; 6.0 - ;; (call $div (f64.promote_f32 (f32.const 0xap+0)) (f64.const 0x2p+0)) ;; 5.0 - ;; (call $sqrt (f64.const 0x10p+0)) ;; 4.0 - ;; (call $min (f64.promote_f32 (f32.const 0x1p+0)) (f64.const 0x2p+0)) ;; 1.0 - ;; (call $max (f64.promote_f32 (f32.const 0x1p+0)) (f64.const 0x2p+0)) ;; 2.0 - ) -) diff --git a/fac.wat b/fac.wat deleted file mode 100644 index a5d8f5f56ea..00000000000 --- a/fac.wat +++ /dev/null @@ -1,24 +0,0 @@ -(module - (func $fac_iter (param i64) (result i64) - (local i64 i64) - (local.set 1 (local.get 0)) - (local.set 2 (i64.const 1)) - (block - (loop - (if - (i64.eq (local.get 1) (i64.const 0)) - (then (br 2)) - (else - (local.set 2 (i64.mul (local.get 1) (local.get 2))) - (local.set 1 (i64.sub (local.get 1) (i64.const 1))) - ) - ) - (br 0) - ) - ) - (local.get 2) - ) - (func $main (export "main") (result i64) - (call $fac_iter (i64.const 25)) - ) -) From 605ada7ad7b84adde3922fa883b1e0f2742aac7c Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 13 Nov 2019 14:53:34 +0800 Subject: [PATCH 131/342] Run cargo fmt. --- lib/runtime-core/src/fault.rs | 2 +- lib/runtime-core/src/state.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index 6a237feca97..776acb4bdfe 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -544,11 +544,11 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> F #[cfg(all(target_os = "linux", target_arch = "x86_64"))] /// Get fault info from siginfo and ucontext. pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> FaultInfo { + use crate::state::x64::XMM; use libc::{ _libc_xmmreg, ucontext_t, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15, REG_R8, REG_R9, REG_RAX, REG_RBP, REG_RBX, REG_RCX, REG_RDI, REG_RDX, REG_RIP, REG_RSI, REG_RSP, }; - use crate::state::x64::XMM; fn read_xmm(reg: &_libc_xmmreg) -> u64 { (reg.element[0] as u64) | ((reg.element[1] as u64) << 32) diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 6933ffcc835..e3ab9ca0fc4 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -2,9 +2,9 @@ //! state could read or updated at runtime. Use cases include generating stack traces, switching //! generated code from one tier to another, or serializing state of a running instace. +use crate::backend::Backend; use std::collections::BTreeMap; use std::ops::Bound::{Included, Unbounded}; -use crate::backend::Backend; /// An index to a register #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] From 66e9184226f6740d8fa353ebf4fcd6f91abb72ed Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 13 Nov 2019 15:06:42 +0800 Subject: [PATCH 132/342] Specify test-threads=1 for singlepass spectests. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e8d11bed05e..a19cc70a1e7 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 test --manifest-path lib/spectests/Cargo.toml --release --features singlepass -- --nocapture --test-threads 1 spectests-cranelift: cargo test --manifest-path lib/spectests/Cargo.toml --release --features clif -- --nocapture From 645519c29cc72addc1254d081ace2c734f91c2d7 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 13 Nov 2019 15:28:04 +0100 Subject: [PATCH 133/342] fix(runtime-c-api) Use `#if defined` instead of `#ifdef`. --- lib/runtime-c-api/build.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/runtime-c-api/build.rs b/lib/runtime-c-api/build.rs index 7c518398c63..4ff1dfb450a 100644 --- a/lib/runtime-c-api/build.rs +++ b/lib/runtime-c-api/build.rs @@ -13,20 +13,20 @@ fn main() { out_wasmer_header_file.push("wasmer"); const WASMER_PRE_HEADER: &str = r#" -#ifndef WASMER_H_MACROS -#define WASMER_H_MACROS -#if MSVC -#ifdef _M_AMD64 -#define ARCH_X86_64 -#endif -#endif +#if !defined(WASMER_H_MACROS) + #define WASMER_H_MACROS + #if defined(MSVC) + #if defined(_M_AMD64) + #define ARCH_X86_64 + #endif + #endif -#if GCC -#ifdef __x86_64__ -#define ARCH_X86_64 -#endif + #if defined(GCC) + #if defined(__x86_64__) + #define ARCH_X86_64 + #endif + #endif #endif -#endif // WASMER_H_MACROS "#; // Generate the C bindings in the `OUT_DIR`. out_wasmer_header_file.set_extension("h"); From b081d17ab0eeb22bbc6639cd80c535682fc90bfc Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 13 Nov 2019 15:28:57 +0100 Subject: [PATCH 134/342] feat(runtime-c-api) Add support for clang in `WASMER_H_MACROS`. --- lib/runtime-c-api/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime-c-api/build.rs b/lib/runtime-c-api/build.rs index 4ff1dfb450a..1978c9934c5 100644 --- a/lib/runtime-c-api/build.rs +++ b/lib/runtime-c-api/build.rs @@ -21,7 +21,7 @@ fn main() { #endif #endif - #if defined(GCC) + #if defined(GCC) || defined(__clang__) #if defined(__x86_64__) #define ARCH_X86_64 #endif From be9d7f2e6e88c0efd75115639a73d0df39be13b6 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 13 Nov 2019 15:29:33 +0100 Subject: [PATCH 135/342] chore(runtime-c-api) Update header files. --- lib/runtime-c-api/wasmer.h | 26 +++++++++++++------------- lib/runtime-c-api/wasmer.hh | 26 +++++++++++++------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index bc4a3ed4fe6..e1175c1fd28 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -1,18 +1,18 @@ -#ifndef WASMER_H_MACROS -#define WASMER_H_MACROS -#if MSVC -#ifdef _M_AMD64 -#define ARCH_X86_64 +#if !defined(WASMER_H_MACROS) + #define WASMER_H_MACROS + #if defined(MSVC) + #if defined(_M_AMD64) + #define ARCH_X86_64 + #endif + #endif + + #if defined(GCC) || defined(__clang__) + #if defined(__x86_64__) + #define ARCH_X86_64 + #endif + #endif #endif -#endif - -#if GCC -#ifdef __x86_64__ -#define ARCH_X86_64 -#endif -#endif -#endif // WASMER_H_MACROS #ifndef WASMER_H diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index acf4b20e797..b4d2c190861 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -1,18 +1,18 @@ -#ifndef WASMER_H_MACROS -#define WASMER_H_MACROS -#if MSVC -#ifdef _M_AMD64 -#define ARCH_X86_64 +#if !defined(WASMER_H_MACROS) + #define WASMER_H_MACROS + #if defined(MSVC) + #if defined(_M_AMD64) + #define ARCH_X86_64 + #endif + #endif + + #if defined(GCC) || defined(__clang__) + #if defined(__x86_64__) + #define ARCH_X86_64 + #endif + #endif #endif -#endif - -#if GCC -#ifdef __x86_64__ -#define ARCH_X86_64 -#endif -#endif -#endif // WASMER_H_MACROS #ifndef WASMER_H From 938dedbbce4d24ec07650d3958155e32631553e6 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 13 Nov 2019 15:35:37 +0100 Subject: [PATCH 136/342] doc(changelog) Add #960. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3bcfcd9518..24d0a57f3ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## **[Unreleased]** +- [#960](https://github.com/wasmerio/wasmer/pull/960) Fix `runtime-c-api` header files when compiled by clang. - [#925](https://github.com/wasmerio/wasmer/pull/925) Host functions can be closures with a captured environment. - [#917](https://github.com/wasmerio/wasmer/pull/917) Host functions (aka imported functions) may not have `&mut vm::Ctx` as first argument, i.e. the presence of the `&mut vm::Ctx` argument is optional. - [#915](https://github.com/wasmerio/wasmer/pull/915) All backends share the same definition of `Trampoline` (defined in `wasmer-runtime-core`). From 82e4d8e6cc596a6563513a38f58d3f055d5784db Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 13 Nov 2019 15:54:09 +0100 Subject: [PATCH 137/342] feat(runtime-core) `func!` supports closures. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch allows to write: ```rs func!(|…| -> … { … }) ``` --- lib/runtime-core/src/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime-core/src/macros.rs b/lib/runtime-core/src/macros.rs index a9dc6721cae..bb0c84fb279 100644 --- a/lib/runtime-core/src/macros.rs +++ b/lib/runtime-core/src/macros.rs @@ -47,7 +47,7 @@ macro_rules! trace { /// Helper macro to create a new `Func` object using the provided function pointer. #[macro_export] macro_rules! func { - ($func:path) => {{ + ($func:expr) => {{ $crate::Func::new($func) }}; } From 7b809a765f2e3134411f57bc46dd1f1c3eaf6cc8 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 13 Nov 2019 15:54:41 +0100 Subject: [PATCH 138/342] doc(runtime-core) Improve documentation of `func!`. This patch explains that `func!` can consume closures. --- lib/runtime-core/src/macros.rs | 38 ++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/lib/runtime-core/src/macros.rs b/lib/runtime-core/src/macros.rs index bb0c84fb279..9005b115d11 100644 --- a/lib/runtime-core/src/macros.rs +++ b/lib/runtime-core/src/macros.rs @@ -45,6 +45,44 @@ macro_rules! trace { } /// Helper macro to create a new `Func` object using the provided function pointer. +/// +/// # Usage +/// +/// Function pointers or closures are supported. Closures can capture +/// their environment (with `move). The first parameter is likely to +/// be of kind `vm::Ctx`, though it can be optional. +/// +/// ``` +/// # use wasmer_runtime_core::{imports, func}; +/// # use wasmer_runtime_core::vm; +/// +/// // A function that has access to `vm::Ctx`. +/// fn func_with_vmctx(_: &mut vm::Ctx, n: i32) -> i32 { +/// n +/// } +/// +/// // A function that cannot access `vm::Ctx`. +/// fn func(n: i32) -> i32 { +/// n +/// } +/// +/// let i = 7; +/// +/// let import_object = imports! { +/// "env" => { +/// "foo" => func!(func_with_vmctx), +/// "bar" => func!(func), +/// // A closure with a captured environment, and an access to `vm::Ctx`. +/// "baz" => func!(move |_: &mut vm::Ctx, n: i32| -> i32 { +/// n + i +/// }), +/// // A closure without a captured environment, and no access to `vm::Ctx`. +/// "qux" => func!(|n: i32| -> i32 { +/// n +/// }), +/// }, +/// }; +/// ``` #[macro_export] macro_rules! func { ($func:expr) => {{ From c4dffd6f59d97c5ae6896aff7dfb6e96a602f13a Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 13 Nov 2019 15:55:45 +0100 Subject: [PATCH 139/342] doc(runtime-core) Fix typos. --- lib/runtime-core/src/macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/runtime-core/src/macros.rs b/lib/runtime-core/src/macros.rs index 9005b115d11..71e8c2e2f7a 100644 --- a/lib/runtime-core/src/macros.rs +++ b/lib/runtime-core/src/macros.rs @@ -94,12 +94,12 @@ macro_rules! func { /// /// [`ImportObject`]: struct.ImportObject.html /// -/// # Note: +/// # Note /// The `import` macro currently only supports /// importing functions. /// /// -/// # Usage: +/// # Usage /// ``` /// # use wasmer_runtime_core::{imports, func}; /// # use wasmer_runtime_core::vm::Ctx; From 9127eaf825f4f8ea9f1f82c7b064e799a5d3f6d8 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 13 Nov 2019 15:09:18 -0800 Subject: [PATCH 140/342] Add categories and keywords to `Cargo.toml`s --- lib/clif-backend/Cargo.toml | 2 ++ lib/emscripten/Cargo.toml | 2 ++ lib/llvm-backend/Cargo.toml | 4 ++++ lib/middleware-common/Cargo.toml | 2 ++ lib/runtime-c-api/Cargo.toml | 2 ++ lib/runtime-core/Cargo.toml | 2 ++ lib/runtime/Cargo.toml | 2 ++ lib/singlepass-backend/Cargo.toml | 2 ++ lib/wasi/Cargo.toml | 2 ++ 9 files changed, 20 insertions(+) diff --git a/lib/clif-backend/Cargo.toml b/lib/clif-backend/Cargo.toml index ff83c131541..b38e40b8266 100644 --- a/lib/clif-backend/Cargo.toml +++ b/lib/clif-backend/Cargo.toml @@ -5,6 +5,8 @@ description = "Wasmer runtime Cranelift compiler backend" license = "MIT" authors = ["The Wasmer Engineering Team "] repository = "https://github.com/wasmerio/wasmer" +keywords = ["wasm", "webassembly", "compiler", "JIT", "AOT"] +categories = ["wasm"] edition = "2018" readme = "README.md" diff --git a/lib/emscripten/Cargo.toml b/lib/emscripten/Cargo.toml index 104312256f3..3db03310fc0 100644 --- a/lib/emscripten/Cargo.toml +++ b/lib/emscripten/Cargo.toml @@ -5,6 +5,8 @@ description = "Wasmer runtime emscripten implementation library" license = "MIT" authors = ["The Wasmer Engineering Team "] repository = "https://github.com/wasmerio/wasmer" +keywords = ["wasm", "webassembly", "ABI", "emscripten", "posix"] +categories = ["wasm"] edition = "2018" [dependencies] diff --git a/lib/llvm-backend/Cargo.toml b/lib/llvm-backend/Cargo.toml index b9c851b07e8..a728a9cec35 100644 --- a/lib/llvm-backend/Cargo.toml +++ b/lib/llvm-backend/Cargo.toml @@ -1,7 +1,11 @@ [package] name = "wasmer-llvm-backend" version = "0.10.1" +license = "MIT" authors = ["The Wasmer Engineering Team "] +repository = "https://github.com/wasmerio/wasmer" +keywords = ["wasm", "webassembly", "compiler", "JIT", "llvm"] +categories = ["wasm"] edition = "2018" readme = "README.md" diff --git a/lib/middleware-common/Cargo.toml b/lib/middleware-common/Cargo.toml index 5840729d632..1c325183df1 100644 --- a/lib/middleware-common/Cargo.toml +++ b/lib/middleware-common/Cargo.toml @@ -5,6 +5,8 @@ repository = "https://github.com/wasmerio/wasmer" description = "Wasmer runtime common middlewares" license = "MIT" authors = ["The Wasmer Engineering Team "] +keywords = ["wasm", "webassembly", "middleware", "metering"] +categories = ["wasm"] edition = "2018" [dependencies] diff --git a/lib/runtime-c-api/Cargo.toml b/lib/runtime-c-api/Cargo.toml index cc689e8892d..90d97ff8220 100644 --- a/lib/runtime-c-api/Cargo.toml +++ b/lib/runtime-c-api/Cargo.toml @@ -5,6 +5,8 @@ description = "Wasmer C API library" license = "MIT" authors = ["The Wasmer Engineering Team "] repository = "https://github.com/wasmerio/wasmer" +keywords = ["wasm", "webassembly", "runtime"] +categories = ["wasm"] edition = "2018" readme = "README.md" diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml index 0acbe718ede..3d1b856ffdf 100644 --- a/lib/runtime-core/Cargo.toml +++ b/lib/runtime-core/Cargo.toml @@ -5,6 +5,8 @@ description = "Wasmer runtime core library" license = "MIT" authors = ["The Wasmer Engineering Team "] repository = "https://github.com/wasmerio/wasmer" +keywords = ["wasm", "webassembly", "runtime"] +categories = ["wasm"] edition = "2018" [dependencies] diff --git a/lib/runtime/Cargo.toml b/lib/runtime/Cargo.toml index 6e6be013cd0..8e272815a84 100644 --- a/lib/runtime/Cargo.toml +++ b/lib/runtime/Cargo.toml @@ -5,6 +5,8 @@ description = "Wasmer runtime library" license = "MIT" authors = ["The Wasmer Engineering Team "] repository = "https://github.com/wasmerio/wasmer" +keywords = ["wasm", "webassembly", "runtime", "sandbox", "secure"] +categories = ["wasm", "api-bindings"] edition = "2018" readme = "README.md" diff --git a/lib/singlepass-backend/Cargo.toml b/lib/singlepass-backend/Cargo.toml index 291d44455c9..5c28ff5e139 100644 --- a/lib/singlepass-backend/Cargo.toml +++ b/lib/singlepass-backend/Cargo.toml @@ -5,6 +5,8 @@ repository = "https://github.com/wasmerio/wasmer" description = "Wasmer runtime single pass compiler backend" license = "MIT" authors = ["The Wasmer Engineering Team "] +keywords = ["wasm", "webassembly", "compiler", "JIT", "AOT"] +categories = ["wasm"] edition = "2018" readme = "README.md" diff --git a/lib/wasi/Cargo.toml b/lib/wasi/Cargo.toml index 8a85acc2d07..6341ffb54f8 100644 --- a/lib/wasi/Cargo.toml +++ b/lib/wasi/Cargo.toml @@ -5,6 +5,8 @@ description = "Wasmer runtime WASI implementation library" license = "MIT" authors = ["The Wasmer Engineering Team "] repository = "https://github.com/wasmerio/wasmer" +keywords = ["wasm", "webassembly", "wasi", "sandbox", "ABI"] +categories = ["wasm"] edition = "2018" [dependencies] From 929bff9df871162abe980d7d8367bb9ebb1e0567 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Wed, 13 Nov 2019 22:59:21 -0600 Subject: [PATCH 141/342] Add deny missing docs to runtime lib --- lib/runtime/src/cache.rs | 4 ++++ lib/runtime/src/lib.rs | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/lib/runtime/src/cache.rs b/lib/runtime/src/cache.rs index fe39b512aea..7cc4386af3e 100644 --- a/lib/runtime/src/cache.rs +++ b/lib/runtime/src/cache.rs @@ -1,3 +1,7 @@ +//! The cache module provides the common data structures used by compiler backends to allow +//! serializing compiled wasm code to a binary format. The binary format can be persisted, +//! and loaded to allow skipping compilation and fast startup. + use crate::Module; use memmap::Mmap; use std::{ diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index aedd938ae69..ad47226fd36 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -1,5 +1,6 @@ #![deny( dead_code, + missing_docs, nonstandard_style, unused_imports, unused_mut, @@ -104,6 +105,8 @@ pub use wasmer_runtime_core::{compile_with, validate}; pub use wasmer_runtime_core::{func, imports}; pub mod memory { + //! The memory module contains the implementation data structures and helper functions used to + //! manipulate and access wasm memory. pub use wasmer_runtime_core::memory::{Atomically, Memory, MemoryView}; } @@ -117,6 +120,8 @@ pub mod wasm { } pub mod error { + //! The error module contains the data structures and helper functions used to implement errors that + //! are produced and returned from the wasmer runtime. pub use wasmer_runtime_core::cache::Error as CacheError; pub use wasmer_runtime_core::error::*; } From 42b02bee7175bf9228aeb655eb2ce79cf114451f Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 14 Nov 2019 14:37:06 +0100 Subject: [PATCH 142/342] fix(runtime-c-api) Write macros at column 0. --- lib/runtime-c-api/build.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/lib/runtime-c-api/build.rs b/lib/runtime-c-api/build.rs index 1978c9934c5..7750b00813d 100644 --- a/lib/runtime-c-api/build.rs +++ b/lib/runtime-c-api/build.rs @@ -14,19 +14,21 @@ fn main() { const WASMER_PRE_HEADER: &str = r#" #if !defined(WASMER_H_MACROS) - #define WASMER_H_MACROS - #if defined(MSVC) - #if defined(_M_AMD64) - #define ARCH_X86_64 - #endif - #endif +#define WASMER_H_MACROS - #if defined(GCC) || defined(__clang__) - #if defined(__x86_64__) - #define ARCH_X86_64 - #endif - #endif +#if defined(MSVC) +#if defined(_M_AMD64) +#define ARCH_X86_64 #endif +#endif + +#if defined(GCC) || defined(__clang__) +#if defined(__x86_64__) +#define ARCH_X86_64 +#endif +#endif + +#endif // WASMER_H_MACROS "#; // Generate the C bindings in the `OUT_DIR`. out_wasmer_header_file.set_extension("h"); From 987b0765c0ea4c675af6f32203f27e2e13f1e5f1 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 14 Nov 2019 14:37:55 +0100 Subject: [PATCH 143/342] chore(runtime-c-api) Update header files. --- lib/runtime-c-api/wasmer.h | 26 ++++++++++++++------------ lib/runtime-c-api/wasmer.hh | 26 ++++++++++++++------------ 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index e1175c1fd28..836a41df215 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -1,19 +1,21 @@ #if !defined(WASMER_H_MACROS) - #define WASMER_H_MACROS - #if defined(MSVC) - #if defined(_M_AMD64) - #define ARCH_X86_64 - #endif - #endif - - #if defined(GCC) || defined(__clang__) - #if defined(__x86_64__) - #define ARCH_X86_64 - #endif - #endif +#define WASMER_H_MACROS + +#if defined(MSVC) +#if defined(_M_AMD64) +#define ARCH_X86_64 +#endif +#endif + +#if defined(GCC) || defined(__clang__) +#if defined(__x86_64__) +#define ARCH_X86_64 +#endif #endif +#endif // WASMER_H_MACROS + #ifndef WASMER_H #define WASMER_H diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index b4d2c190861..79c350d6080 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -1,19 +1,21 @@ #if !defined(WASMER_H_MACROS) - #define WASMER_H_MACROS - #if defined(MSVC) - #if defined(_M_AMD64) - #define ARCH_X86_64 - #endif - #endif - - #if defined(GCC) || defined(__clang__) - #if defined(__x86_64__) - #define ARCH_X86_64 - #endif - #endif +#define WASMER_H_MACROS + +#if defined(MSVC) +#if defined(_M_AMD64) +#define ARCH_X86_64 +#endif +#endif + +#if defined(GCC) || defined(__clang__) +#if defined(__x86_64__) +#define ARCH_X86_64 +#endif #endif +#endif // WASMER_H_MACROS + #ifndef WASMER_H #define WASMER_H From 342974effdd829867c6b4a1c1ce2a085446f40bd Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 15 Nov 2019 00:23:10 +0800 Subject: [PATCH 144/342] Comment out failing test. --- lib/spectests/spectests/start.wast | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/spectests/spectests/start.wast b/lib/spectests/spectests/start.wast index 6719edba871..38c4f668783 100644 --- a/lib/spectests/spectests/start.wast +++ b/lib/spectests/spectests/start.wast @@ -89,10 +89,10 @@ (start $main) ) -(module - (func $print (import "spectest" "print")) - (start $print) -) +;; (module +;; (func $print (import "spectest" "print")) +;; (start $print) +;; ) (assert_trap (module (func $main (unreachable)) (start $main)) From 7b3093ff7fa0db60d90950ae1bde313d1e2a06d0 Mon Sep 17 00:00:00 2001 From: Syrus Date: Thu, 14 Nov 2019 12:07:53 -0800 Subject: [PATCH 145/342] Added invoke option to the command --- src/bin/wasmer.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 6195e60a612..7af5df3e258 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -132,6 +132,10 @@ struct Run { )] backend: Backend, + /// Invoke a specified function + #[structopt(long = "invoke", short = "i")] + invoke: Option, + /// Emscripten symbol map #[structopt(long = "em-symbol-map", parse(from_os_str), group = "emscripten")] em_symbol_map: Option, @@ -683,8 +687,12 @@ fn execute_wasm(options: &Run) -> Result<(), String> { args.push(Value::I32(x)); } + let invoke_fn = match options.invoke.as_ref() { + Some(fun) => fun, + _ => "main", + }; instance - .dyn_func("main") + .dyn_func(&invoke_fn) .map_err(|e| format!("{:?}", e))? .call(&args) .map_err(|e| format!("{:?}", e))?; From d0960dc390f4c1e951d4d6c00ae7273c14d50bc5 Mon Sep 17 00:00:00 2001 From: Syrus Date: Thu, 14 Nov 2019 12:10:44 -0800 Subject: [PATCH 146/342] Added changes to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3bcfcd9518..3f3f4a4d991 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## **[Unreleased]** +- [#968](https://github.com/wasmerio/wasmer/pull/968) Added `--invoke` option to the command - [#925](https://github.com/wasmerio/wasmer/pull/925) Host functions can be closures with a captured environment. - [#917](https://github.com/wasmerio/wasmer/pull/917) Host functions (aka imported functions) may not have `&mut vm::Ctx` as first argument, i.e. the presence of the `&mut vm::Ctx` argument is optional. - [#915](https://github.com/wasmerio/wasmer/pull/915) All backends share the same definition of `Trampoline` (defined in `wasmer-runtime-core`). From 3cb7a4bf761706f16b6735dbd338bf46bfff2638 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 14 Nov 2019 19:23:20 -0800 Subject: [PATCH 147/342] Use Rust 1.38. Fixed #970 --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 43fcda359fc..6affe470faf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM circleci/rust:1.33.0-stretch as wasmer-build-env +FROM circleci/rust:1.38.0-stretch as wasmer-build-env RUN sudo apt-get update && \ sudo apt-get install -y --no-install-recommends \ cmake \ @@ -22,4 +22,4 @@ RUN cargo build --release FROM debian:stretch AS wasmer WORKDIR /root/ COPY --from=wasmer-build /home/circleci/wasmer/target/release/wasmer . -ENTRYPOINT ["./wasmer"] \ No newline at end of file +ENTRYPOINT ["./wasmer"] From c15b9fcdcd11b86b27c1fa9d41f3e9f212ce91c5 Mon Sep 17 00:00:00 2001 From: Syrus Date: Fri, 15 Nov 2019 09:47:38 -0800 Subject: [PATCH 148/342] Add examples dir to Docker file. Fix #970 --- .dockerignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.dockerignore b/.dockerignore index e861ea7b657..29fd6ce6b1e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,5 +2,6 @@ ** !lib/** !src/** +!examples/** !Cargo.toml !Cargo.lock \ No newline at end of file From f3b7c6b321b06dad25d9892b0c3c4b302843a6b0 Mon Sep 17 00:00:00 2001 From: Syrus Date: Fri, 15 Nov 2019 10:41:18 -0800 Subject: [PATCH 149/342] Improved wasmer invoke based on feedback --- src/bin/wasmer.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 7af5df3e258..48f43c917a1 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -687,10 +687,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { args.push(Value::I32(x)); } - let invoke_fn = match options.invoke.as_ref() { - Some(fun) => fun, - _ => "main", - }; + let invoke_fn = options.invoke.clone().unwrap_or("main".to_owned()); instance .dyn_func(&invoke_fn) .map_err(|e| format!("{:?}", e))? From 3d3636059a7dbb06b20fa915d6f5fbf3e92774bb Mon Sep 17 00:00:00 2001 From: Syrus Date: Fri, 15 Nov 2019 14:04:48 -0800 Subject: [PATCH 150/342] Revert "Improved wasmer invoke based on feedback" This reverts commit f3b7c6b321b06dad25d9892b0c3c4b302843a6b0. --- src/bin/wasmer.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 48f43c917a1..7af5df3e258 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -687,7 +687,10 @@ fn execute_wasm(options: &Run) -> Result<(), String> { args.push(Value::I32(x)); } - let invoke_fn = options.invoke.clone().unwrap_or("main".to_owned()); + let invoke_fn = match options.invoke.as_ref() { + Some(fun) => fun, + _ => "main", + }; instance .dyn_func(&invoke_fn) .map_err(|e| format!("{:?}", e))? From ebe8da7bd3479d824f019876b78671821430e030 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 15 Nov 2019 13:07:05 -0800 Subject: [PATCH 151/342] When accessing memory, use byte aligned accesses. LLVM's instcombine will attempt to bump the alignment when it can prove that it's safe to do so. Fixes #969. --- lib/llvm-backend/src/code.rs | 176 ++++++++++++++++++++++++++++------- 1 file changed, 141 insertions(+), 35 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index b2f5b62d97a..ac7ac92bbc3 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -4469,6 +4469,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 4, )?; let result = builder.build_load(effective_address, &state.var_name()); + result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4492,6 +4497,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 8, )?; let result = builder.build_load(effective_address, &state.var_name()); + result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4515,6 +4525,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 4, )?; let result = builder.build_load(effective_address, &state.var_name()); + result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4538,6 +4553,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 8, )?; let result = builder.build_load(effective_address, &state.var_name()); + result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4561,6 +4581,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 16, )?; let result = builder.build_load(effective_address, &state.var_name()); + result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4586,6 +4611,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 4, )?; let store = builder.build_store(effective_address, value); + store.set_alignment(1).unwrap(); tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I64Store { ref memarg } => { @@ -4603,6 +4629,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 8, )?; let store = builder.build_store(effective_address, value); + store.set_alignment(1).unwrap(); tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::F32Store { ref memarg } => { @@ -4621,6 +4648,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 4, )?; let store = builder.build_store(effective_address, v); + store.set_alignment(1).unwrap(); tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::F64Store { ref memarg } => { @@ -4639,6 +4667,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 8, )?; let store = builder.build_store(effective_address, v); + store.set_alignment(1).unwrap(); tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::V128Store { ref memarg } => { @@ -4657,6 +4686,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 16, )?; let store = builder.build_store(effective_address, v); + store.set_alignment(1).unwrap(); tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I32Load8S { ref memarg } => { @@ -4672,9 +4702,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i8_ptr_ty, 1, )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); + let narrow_result = builder.build_load(effective_address, &state.var_name()); + narrow_result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4682,8 +4715,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { narrow_result.as_instruction_value().unwrap(), Some(0), ); - let result = - builder.build_int_s_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); + let result = builder.build_int_s_extend( + narrow_result.into_int_value(), + intrinsics.i32_ty, + &state.var_name(), + ); state.push1(result); } Operator::I32Load16S { ref memarg } => { @@ -4700,6 +4736,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 2, )?; let narrow_result = builder.build_load(effective_address, &state.var_name()); + narrow_result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4730,6 +4771,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + narrow_result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4757,6 +4803,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + narrow_result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4781,9 +4832,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i32_ptr_ty, 4, )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); + let narrow_result = builder.build_load(effective_address, &state.var_name()); + narrow_result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4791,8 +4845,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { narrow_result.as_instruction_value().unwrap(), Some(0), ); - let result = - builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); + let result = builder.build_int_s_extend( + narrow_result.into_int_value(), + intrinsics.i64_ty, + &state.var_name(), + ); state.push1(result); } @@ -4809,9 +4866,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i8_ptr_ty, 1, )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); + let narrow_result = builder.build_load(effective_address, &state.var_name()); + narrow_result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4819,8 +4879,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { narrow_result.as_instruction_value().unwrap(), Some(0), ); - let result = - builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); + let result = builder.build_int_z_extend( + narrow_result.into_int_value(), + intrinsics.i32_ty, + &state.var_name(), + ); state.push1(result); } Operator::I32Load16U { ref memarg } => { @@ -4836,9 +4899,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i16_ptr_ty, 2, )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); + let narrow_result = builder.build_load(effective_address, &state.var_name()); + narrow_result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4846,8 +4912,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { narrow_result.as_instruction_value().unwrap(), Some(0), ); - let result = - builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); + let result = builder.build_int_z_extend( + narrow_result.into_int_value(), + intrinsics.i32_ty, + &state.var_name(), + ); state.push1(result); } Operator::I64Load8U { ref memarg } => { @@ -4863,9 +4932,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i8_ptr_ty, 1, )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); + let narrow_result = builder.build_load(effective_address, &state.var_name()); + narrow_result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4873,8 +4945,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { narrow_result.as_instruction_value().unwrap(), Some(0), ); - let result = - builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); + let result = builder.build_int_z_extend( + narrow_result.into_int_value(), + intrinsics.i64_ty, + &state.var_name(), + ); state.push1(result); } Operator::I64Load16U { ref memarg } => { @@ -4890,9 +4965,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i16_ptr_ty, 2, )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); + let narrow_result = builder.build_load(effective_address, &state.var_name()); + narrow_result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4900,8 +4978,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { narrow_result.as_instruction_value().unwrap(), Some(0), ); - let result = - builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); + let result = builder.build_int_z_extend( + narrow_result.into_int_value(), + intrinsics.i64_ty, + &state.var_name(), + ); state.push1(result); } Operator::I64Load32U { ref memarg } => { @@ -4917,9 +4998,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i32_ptr_ty, 4, )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); + let narrow_result = builder.build_load(effective_address, &state.var_name()); + narrow_result + .as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -4927,8 +5011,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { narrow_result.as_instruction_value().unwrap(), Some(0), ); - let result = - builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); + let result = builder.build_int_z_extend( + narrow_result.into_int_value(), + intrinsics.i64_ty, + &state.var_name(), + ); state.push1(result); } @@ -4949,6 +5036,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let narrow_value = builder.build_int_truncate(value, intrinsics.i8_ty, &state.var_name()); let store = builder.build_store(effective_address, narrow_value); + store.set_alignment(1).unwrap(); tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I32Store16 { ref memarg } | Operator::I64Store16 { ref memarg } => { @@ -4968,6 +5056,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let narrow_value = builder.build_int_truncate(value, intrinsics.i16_ty, &state.var_name()); let store = builder.build_store(effective_address, narrow_value); + store.set_alignment(1).unwrap(); tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I64Store32 { ref memarg } => { @@ -4987,6 +5076,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let narrow_value = builder.build_int_truncate(value, intrinsics.i32_ty, &state.var_name()); let store = builder.build_store(effective_address, narrow_value); + store.set_alignment(1).unwrap(); tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I8x16Neg => { @@ -5291,6 +5381,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 1, )?; let elem = builder.build_load(effective_address, ""); + elem.as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -5322,6 +5416,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 2, )?; let elem = builder.build_load(effective_address, ""); + elem.as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -5353,6 +5451,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 4, )?; let elem = builder.build_load(effective_address, ""); + elem.as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, @@ -5384,6 +5486,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 8, )?; let elem = builder.build_load(effective_address, ""); + elem.as_instruction_value() + .unwrap() + .set_alignment(1) + .unwrap(); tbaa_label( self.module.clone(), intrinsics, From ecc82a7cabdf495b6fce3d6f579745f42c9a7606 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 15 Nov 2019 13:15:19 -0800 Subject: [PATCH 152/342] Add changelog entry. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41a4c269131..fdfb6d8bef8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## **[Unreleased]** - [#968](https://github.com/wasmerio/wasmer/pull/968) Added `--invoke` option to the command +- [#971](https://github.com/wasmerio/wasmer/pull/971) In LLVM backend, use unaligned loads and stores for non-atomic accesses to wasmer memory. - [#960](https://github.com/wasmerio/wasmer/pull/960) Fix `runtime-c-api` header files when compiled by clang. - [#925](https://github.com/wasmerio/wasmer/pull/925) Host functions can be closures with a captured environment. - [#917](https://github.com/wasmerio/wasmer/pull/917) Host functions (aka imported functions) may not have `&mut vm::Ctx` as first argument, i.e. the presence of the `&mut vm::Ctx` argument is optional. From cebcb4c9276b9481106684e29de8f888287cbdf7 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Fri, 15 Nov 2019 14:55:53 -0800 Subject: [PATCH 153/342] Prepare for 0.10.2 release --- CHANGELOG.md | 2 + Cargo.lock | 146 ++++++++++++------------- 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 | 8 +- lib/runtime-core-tests/Cargo.toml | 10 +- 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 | 4 +- scripts/update_version_numbers.sh | 4 +- src/installer/wasmer.iss | 2 +- 21 files changed, 135 insertions(+), 133 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41a4c269131..50dfff45a09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## **[Unreleased]** +## 0.10.2 - 2019-11-15 + - [#968](https://github.com/wasmerio/wasmer/pull/968) Added `--invoke` option to the command - [#960](https://github.com/wasmerio/wasmer/pull/960) Fix `runtime-c-api` header files when compiled by clang. - [#925](https://github.com/wasmerio/wasmer/pull/925) Host functions can be closures with a captured environment. diff --git a/Cargo.lock b/Cargo.lock index 52ff96ffcbb..24fa874a31a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -720,8 +720,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.10.1", - "wasmer-runtime-core 0.10.1", + "wasmer-runtime 0.10.2", + "wasmer-runtime-core 0.10.2", ] [[package]] @@ -1333,7 +1333,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wasmer" -version = "0.10.1" +version = "0.10.2" 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)", @@ -1343,24 +1343,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.10.1", - "wasmer-dev-utils 0.10.1", - "wasmer-emscripten 0.10.1", - "wasmer-emscripten-tests 0.10.1", + "wasmer-clif-backend 0.10.2", + "wasmer-dev-utils 0.10.2", + "wasmer-emscripten 0.10.2", + "wasmer-emscripten-tests 0.10.2", "wasmer-kernel-loader 0.1.0", - "wasmer-llvm-backend 0.10.1", - "wasmer-middleware-common 0.10.1", - "wasmer-middleware-common-tests 0.10.1", - "wasmer-runtime 0.10.1", - "wasmer-runtime-core 0.10.1", - "wasmer-singlepass-backend 0.10.1", - "wasmer-wasi 0.10.1", - "wasmer-wasi-tests 0.10.1", + "wasmer-llvm-backend 0.10.2", + "wasmer-middleware-common 0.10.2", + "wasmer-middleware-common-tests 0.10.2", + "wasmer-runtime 0.10.2", + "wasmer-runtime-core 0.10.2", + "wasmer-singlepass-backend 0.10.2", + "wasmer-wasi 0.10.2", + "wasmer-wasi-tests 0.10.2", ] [[package]] name = "wasmer-clif-backend" -version = "0.10.1" +version = "0.10.2" 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)", @@ -1376,8 +1376,8 @@ 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.10.1", - "wasmer-win-exception-handler 0.10.1", + "wasmer-runtime-core 0.10.2", + "wasmer-win-exception-handler 0.10.2", "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)", ] @@ -1409,35 +1409,35 @@ dependencies = [ [[package]] name = "wasmer-dev-utils" -version = "0.10.1" +version = "0.10.2" dependencies = [ "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmer-emscripten" -version = "0.10.1" +version = "0.10.2" 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)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.10.1", + "wasmer-runtime-core 0.10.2", ] [[package]] name = "wasmer-emscripten-tests" -version = "0.10.1" +version = "0.10.2" 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.10.1", - "wasmer-dev-utils 0.10.1", - "wasmer-emscripten 0.10.1", - "wasmer-llvm-backend 0.10.1", - "wasmer-runtime-core 0.10.1", - "wasmer-singlepass-backend 0.10.1", + "wasmer-clif-backend 0.10.2", + "wasmer-dev-utils 0.10.2", + "wasmer-emscripten 0.10.2", + "wasmer-llvm-backend 0.10.2", + "wasmer-runtime-core 0.10.2", + "wasmer-singlepass-backend 0.10.2", ] [[package]] @@ -1445,12 +1445,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.10.1", + "wasmer-runtime-core 0.10.2", ] [[package]] name = "wasmer-llvm-backend" -version = "0.10.1" +version = "0.10.2" 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)", @@ -1464,60 +1464,60 @@ dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.12 (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.10.1", + "wasmer-runtime-core 0.10.2", "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.10.1" +version = "0.10.2" dependencies = [ - "wasmer-runtime-core 0.10.1", + "wasmer-runtime-core 0.10.2", ] [[package]] name = "wasmer-middleware-common-tests" -version = "0.10.1" +version = "0.10.2" 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.10.1", - "wasmer-llvm-backend 0.10.1", - "wasmer-middleware-common 0.10.1", - "wasmer-runtime-core 0.10.1", - "wasmer-singlepass-backend 0.10.1", + "wasmer-clif-backend 0.10.2", + "wasmer-llvm-backend 0.10.2", + "wasmer-middleware-common 0.10.2", + "wasmer-runtime-core 0.10.2", + "wasmer-singlepass-backend 0.10.2", ] [[package]] name = "wasmer-runtime" -version = "0.10.1" +version = "0.10.2" 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.10.1", - "wasmer-llvm-backend 0.10.1", - "wasmer-runtime-core 0.10.1", - "wasmer-singlepass-backend 0.10.1", + "wasmer-clif-backend 0.10.2", + "wasmer-llvm-backend 0.10.2", + "wasmer-runtime-core 0.10.2", + "wasmer-singlepass-backend 0.10.2", ] [[package]] name = "wasmer-runtime-c-api" -version = "0.10.1" +version = "0.10.2" 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.10.1", - "wasmer-runtime-core 0.10.1", - "wasmer-wasi 0.10.1", + "wasmer-runtime 0.10.2", + "wasmer-runtime-core 0.10.2", + "wasmer-wasi 0.10.2", ] [[package]] name = "wasmer-runtime-core" -version = "0.10.1" +version = "0.10.2" dependencies = [ "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)", @@ -1543,18 +1543,18 @@ dependencies = [ [[package]] name = "wasmer-runtime-core-tests" -version = "0.10.1" +version = "0.10.2" dependencies = [ "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-clif-backend 0.10.1", - "wasmer-llvm-backend 0.10.1", - "wasmer-runtime-core 0.10.1", - "wasmer-singlepass-backend 0.10.1", + "wasmer-clif-backend 0.10.2", + "wasmer-llvm-backend 0.10.2", + "wasmer-runtime-core 0.10.2", + "wasmer-singlepass-backend 0.10.2", ] [[package]] name = "wasmer-singlepass-backend" -version = "0.10.1" +version = "0.10.2" 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)", @@ -1563,24 +1563,24 @@ 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.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.10.1", + "wasmer-runtime-core 0.10.2", ] [[package]] name = "wasmer-spectests" -version = "0.10.1" +version = "0.10.2" 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.10.1", - "wasmer-llvm-backend 0.10.1", - "wasmer-runtime-core 0.10.1", - "wasmer-singlepass-backend 0.10.1", + "wasmer-clif-backend 0.10.2", + "wasmer-llvm-backend 0.10.2", + "wasmer-runtime-core 0.10.2", + "wasmer-singlepass-backend 0.10.2", ] [[package]] name = "wasmer-wasi" -version = "0.10.1" +version = "0.10.2" 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)", @@ -1591,31 +1591,31 @@ dependencies = [ "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.10.1", + "wasmer-runtime-core 0.10.2", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmer-wasi-tests" -version = "0.10.1" +version = "0.10.2" dependencies = [ "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-clif-backend 0.10.1", - "wasmer-dev-utils 0.10.1", - "wasmer-llvm-backend 0.10.1", - "wasmer-runtime 0.10.1", - "wasmer-runtime-core 0.10.1", - "wasmer-singlepass-backend 0.10.1", - "wasmer-wasi 0.10.1", + "wasmer-clif-backend 0.10.2", + "wasmer-dev-utils 0.10.2", + "wasmer-llvm-backend 0.10.2", + "wasmer-runtime 0.10.2", + "wasmer-runtime-core 0.10.2", + "wasmer-singlepass-backend 0.10.2", + "wasmer-wasi 0.10.2", ] [[package]] name = "wasmer-win-exception-handler" -version = "0.10.1" +version = "0.10.2" 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.10.1", + "wasmer-runtime-core 0.10.2", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/Cargo.toml b/Cargo.toml index 3d0c6b7addd..8724d91d4a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer" -version = "0.10.1" +version = "0.10.2" 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 b38e40b8266..e3d5689749d 100644 --- a/lib/clif-backend/Cargo.toml +++ b/lib/clif-backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-clif-backend" -version = "0.10.1" +version = "0.10.2" description = "Wasmer runtime Cranelift compiler backend" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -11,7 +11,7 @@ edition = "2018" readme = "README.md" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } cranelift-native = "0.44.0" cranelift-codegen = "0.44.0" cranelift-entity = "0.44.0" @@ -37,7 +37,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.10.1" } +wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.10.2" } [features] debug = ["wasmer-runtime-core/debug"] diff --git a/lib/dev-utils/Cargo.toml b/lib/dev-utils/Cargo.toml index 9dc98607a74..45722b9b6b0 100644 --- a/lib/dev-utils/Cargo.toml +++ b/lib/dev-utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-dev-utils" -version = "0.10.1" +version = "0.10.2" 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 8cb8248f4ad..49880090faa 100644 --- a/lib/emscripten-tests/Cargo.toml +++ b/lib/emscripten-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-emscripten-tests" -version = "0.10.1" +version = "0.10.2" 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.10.1" } -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.10.1" } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.1", optional = true } -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.1", optional = true } +wasmer-emscripten = { path = "../emscripten", version = "0.10.2" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.10.2" } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.2", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.2", optional = true } [dev-dependencies] wabt = "0.9.1" -wasmer-dev-utils = { path = "../dev-utils", version = "0.10.1"} +wasmer-dev-utils = { path = "../dev-utils", version = "0.10.2"} [build-dependencies] glob = "0.3" diff --git a/lib/emscripten/Cargo.toml b/lib/emscripten/Cargo.toml index 3db03310fc0..27606a1538c 100644 --- a/lib/emscripten/Cargo.toml +++ b/lib/emscripten/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-emscripten" -version = "0.10.1" +version = "0.10.2" description = "Wasmer runtime emscripten implementation library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -14,7 +14,7 @@ byteorder = "1.3" lazy_static = "1.4" libc = "0.2.60" time = "0.1" -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } [target.'cfg(windows)'.dependencies] getrandom = "0.1" diff --git a/lib/llvm-backend/Cargo.toml b/lib/llvm-backend/Cargo.toml index a728a9cec35..c3fe61811ff 100644 --- a/lib/llvm-backend/Cargo.toml +++ b/lib/llvm-backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-llvm-backend" -version = "0.10.1" +version = "0.10.2" license = "MIT" authors = ["The Wasmer Engineering Team "] repository = "https://github.com/wasmerio/wasmer" @@ -10,7 +10,7 @@ edition = "2018" readme = "README.md" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } 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 c55a5a37a6b..5eb36d95905 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.10.1" +version = "0.10.2" 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.10.1" } -wasmer-middleware-common = { path = "../middleware-common", version = "0.10.1" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.10.1" } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.1", optional = true } -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.1", optional = true } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } +wasmer-middleware-common = { path = "../middleware-common", version = "0.10.2" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.10.2" } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.2", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.2", optional = true } [features] clif = [] diff --git a/lib/middleware-common/Cargo.toml b/lib/middleware-common/Cargo.toml index 1c325183df1..e151c7f3b38 100644 --- a/lib/middleware-common/Cargo.toml +++ b/lib/middleware-common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-middleware-common" -version = "0.10.1" +version = "0.10.2" repository = "https://github.com/wasmerio/wasmer" description = "Wasmer runtime common middlewares" license = "MIT" @@ -10,4 +10,4 @@ categories = ["wasm"] edition = "2018" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } diff --git a/lib/runtime-c-api/Cargo.toml b/lib/runtime-c-api/Cargo.toml index 90d97ff8220..cae6cd7441e 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.10.1" +version = "0.10.2" description = "Wasmer C API library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -19,17 +19,17 @@ libc = "0.2.60" [dependencies.wasmer-runtime] default-features = false path = "../runtime" -version = "0.10.1" +version = "0.10.2" [dependencies.wasmer-runtime-core] default-features = false path = "../runtime-core" -version = "0.10.1" +version = "0.10.2" [dependencies.wasmer-wasi] default-features = false path = "../wasi" -version = "0.10.1" +version = "0.10.2" optional = true [features] diff --git a/lib/runtime-core-tests/Cargo.toml b/lib/runtime-core-tests/Cargo.toml index 73cbb03ce4e..0191d0e827f 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.10.1" +version = "0.10.2" description = "Tests for the Wasmer runtime core crate" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -9,10 +9,10 @@ publish = false [dependencies] wabt = "0.9.1" -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.10.1", optional = true } -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.1", optional = true } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.1", optional = true } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.10.2", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.2", optional = true } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.2", optional = true } [features] default = ["backend-cranelift"] diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml index 8d89d9fa192..e269ad15a0a 100644 --- a/lib/runtime-core/Cargo.toml +++ b/lib/runtime-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-runtime-core" -version = "0.10.1" +version = "0.10.2" 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 8e272815a84..902ea37ac38 100644 --- a/lib/runtime/Cargo.toml +++ b/lib/runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-runtime" -version = "0.10.1" +version = "0.10.2" description = "Wasmer runtime library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -11,17 +11,17 @@ edition = "2018" readme = "README.md" [dependencies] -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.1", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.2", optional = true } lazy_static = "1.4" memmap = "0.7" [dependencies.wasmer-runtime-core] path = "../runtime-core" -version = "0.10.1" +version = "0.10.2" [dependencies.wasmer-clif-backend] path = "../clif-backend" -version = "0.10.1" +version = "0.10.2" optional = true [dev-dependencies] diff --git a/lib/singlepass-backend/Cargo.toml b/lib/singlepass-backend/Cargo.toml index 5c28ff5e139..c985546cc45 100644 --- a/lib/singlepass-backend/Cargo.toml +++ b/lib/singlepass-backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-singlepass-backend" -version = "0.10.1" +version = "0.10.2" repository = "https://github.com/wasmerio/wasmer" description = "Wasmer runtime single pass compiler backend" license = "MIT" @@ -11,7 +11,7 @@ edition = "2018" readme = "README.md" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } 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 82e5aca2436..54c17ccc1c5 100644 --- a/lib/spectests/Cargo.toml +++ b/lib/spectests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-spectests" -version = "0.10.1" +version = "0.10.2" 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.10.1" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.10.1" } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.1", optional = true } -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.1", optional = true } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.10.2" } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.2", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.2", optional = true } [build-dependencies] wabt = "0.9.1" diff --git a/lib/wasi-tests/Cargo.toml b/lib/wasi-tests/Cargo.toml index 35aa31c0ea5..05544c7a3de 100644 --- a/lib/wasi-tests/Cargo.toml +++ b/lib/wasi-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-wasi-tests" -version = "0.10.1" +version = "0.10.2" 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.10.1" } -wasmer-runtime = { path = "../runtime", version = "0.10.1" } -wasmer-wasi = { path = "../wasi", version = "0.10.1" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } +wasmer-runtime = { path = "../runtime", version = "0.10.2" } +wasmer-wasi = { path = "../wasi", version = "0.10.2" } # hack to get tests to work -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.1", optional = true } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.1", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.2", optional = true } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.2", optional = true } [build-dependencies] glob = "0.3" [dev-dependencies] -wasmer-clif-backend = { path = "../clif-backend", version = "0.10.1" } -wasmer-dev-utils = { path = "../dev-utils", version = "0.10.1"} +wasmer-clif-backend = { path = "../clif-backend", version = "0.10.2" } +wasmer-dev-utils = { path = "../dev-utils", version = "0.10.2"} [features] clif = [] diff --git a/lib/wasi/Cargo.toml b/lib/wasi/Cargo.toml index 6341ffb54f8..ff0220aa47b 100644 --- a/lib/wasi/Cargo.toml +++ b/lib/wasi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-wasi" -version = "0.10.1" +version = "0.10.2" description = "Wasmer runtime WASI implementation library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -19,7 +19,7 @@ getrandom = "0.1" time = "0.1" typetag = "0.1" serde = { version = "1", features = ["derive"] } -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } [target.'cfg(windows)'.dependencies] winapi = "0.3" diff --git a/lib/win-exception-handler/Cargo.toml b/lib/win-exception-handler/Cargo.toml index 4c0332e5348..ef1cf619a90 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.10.1" +version = "0.10.2" description = "Wasmer runtime exception handling for Windows" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -8,7 +8,7 @@ repository = "https://github.com/wasmerio/wasmer" edition = "2018" [target.'cfg(windows)'.dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } winapi = { version = "0.3.8", features = ["winbase", "errhandlingapi", "minwindef", "minwinbase", "winnt"] } libc = "0.2.60" diff --git a/scripts/update_version_numbers.sh b/scripts/update_version_numbers.sh index 7a8585bfba9..2ee5bb0823e 100755 --- a/scripts/update_version_numbers.sh +++ b/scripts/update_version_numbers.sh @@ -1,5 +1,5 @@ -PREVIOUS_VERSION='0.10.0' -NEXT_VERSION='0.10.1' +PREVIOUS_VERSION='0.10.1' +NEXT_VERSION='0.10.2' # 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 3279cd9f1d8..146680b05ac 100644 --- a/src/installer/wasmer.iss +++ b/src/installer/wasmer.iss @@ -1,6 +1,6 @@ [Setup] AppName=Wasmer -AppVersion=0.10.1 +AppVersion=0.10.2 DefaultDirName={pf}\Wasmer DefaultGroupName=Wasmer Compression=lzma2 From 3b2d751c5595126fe90aabab8d1cdf8dd871f41f Mon Sep 17 00:00:00 2001 From: anb Date: Wed, 13 Nov 2019 12:31:50 -0800 Subject: [PATCH 154/342] Enable compilation for specific target By exposing the target information through `CompilerConfig`, compiler(only LLVM at the moment) could create a machine with different CPU feature flags other than current host, which makes it capable to "cross compile" to some degree. Update #959 --- lib/clif-backend/src/code.rs | 4 +++ lib/llvm-backend/src/code.rs | 35 ++++++++++++++++------- lib/runtime-core/src/backend.rs | 5 ++++ lib/runtime-core/src/codegen.rs | 16 ++++++++++- lib/singlepass-backend/src/codegen_x64.rs | 4 +++ src/bin/kwasmd.rs | 1 + src/bin/wasmer.rs | 1 + 7 files changed, 54 insertions(+), 12 deletions(-) diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index 1bd1958e3de..d86d19b4f0f 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -54,6 +54,10 @@ impl ModuleCodeGenerator } } + fn new_with_target(_: Option, _: Option, _: Option) -> Self { + unimplemented!("cross compilation is not available for clif backend") + } + fn backend_id() -> Backend { Backend::Cranelift } diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index ac7ac92bbc3..0aca846505c 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -8075,24 +8075,37 @@ impl ModuleCodeGenerator for LLVMModuleCodeGenerator { fn new() -> LLVMModuleCodeGenerator { + Self::new_with_target(None, None, None) + } + + fn new_with_target( + triple: Option, + cpu_name: Option, + cpu_features: Option, + ) -> 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 triple = triple.unwrap_or(TargetMachine::get_default_triple().to_string()); + + match triple { + _ if triple.starts_with("x86") => Target::initialize_x86(&InitializationConfig { + asm_parser: true, + asm_printer: true, + base: true, + disassembler: true, + info: true, + machine_code: true, + }), + _ => unimplemented!("compile to target other than x86-64 is not supported"), + } + 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(), + &cpu_name.unwrap_or(TargetMachine::get_host_cpu_name().to_string()), + &cpu_features.unwrap_or(TargetMachine::get_host_cpu_features().to_string()), OptimizationLevel::Aggressive, RelocMode::Static, CodeModel::Large, diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs index f1086de0d68..893874ed934 100644 --- a/lib/runtime-core/src/backend.rs +++ b/lib/runtime-core/src/backend.rs @@ -129,6 +129,11 @@ pub struct CompilerConfig { pub enforce_stack_check: bool, pub track_state: bool, pub features: Features, + + // target info used by LLVM + pub triple: Option, + pub cpu_name: Option, + pub cpu_features: Option, } pub trait Compiler { diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index e96f419e6b4..9e42d80490a 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -74,6 +74,13 @@ pub trait ModuleCodeGenerator, RM: RunnableModule, /// Creates a new module code generator. fn new() -> Self; + /// Creates a new module code generator for specified target. + fn new_with_target( + triple: Option, + cpu_name: Option, + cpu_features: Option, + ) -> Self; + /// Returns the backend id associated with this MCG. fn backend_id() -> Backend; @@ -206,7 +213,14 @@ impl< validate_with_features(wasm, &compiler_config.features)?; } - let mut mcg = MCG::new(); + let mut mcg = match MCG::backend_id() { + Backend::LLVM => MCG::new_with_target( + compiler_config.triple.clone(), + compiler_config.cpu_name.clone(), + compiler_config.cpu_features.clone(), + ), + _ => MCG::new(), + }; let mut chain = (self.middleware_chain_generator)(); let info = crate::parse::read_module( wasm, diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 7a71a289fe2..e4934e3c2ba 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -370,6 +370,10 @@ impl ModuleCodeGenerator } } + fn new_with_target(_: Option, _: Option, _: Option) -> Self { + unimplemented!("cross compilation is not available for singlepass backend") + } + fn backend_id() -> Backend { Backend::Singlepass } diff --git a/src/bin/kwasmd.rs b/src/bin/kwasmd.rs index 62e22b731a7..79949417b10 100644 --- a/src/bin/kwasmd.rs +++ b/src/bin/kwasmd.rs @@ -63,6 +63,7 @@ fn handle_client(mut stream: UnixStream) { enforce_stack_check: true, track_state: false, features: Default::default(), + ..Default::default() }, &SinglePassCompiler::new(), ) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 7af5df3e258..ad9afa97211 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -447,6 +447,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { simd: options.features.simd || options.features.all, threads: options.features.threads || options.features.all, }, + ..Default::default() }, &*compiler, ) From 7631aee4f4d2265e0c38d2f2a40ab991d2c5ded7 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Fri, 15 Nov 2019 21:54:34 -0800 Subject: [PATCH 155/342] Add sign extension spec tests; add sign extension to singlepass --- lib/singlepass-backend/src/codegen_x64.rs | 125 +++++++++++++++++++++- lib/spectests/spectests/conversions.wast | 48 +++++++++ lib/spectests/tests/excludes.txt | 80 +++++++------- lib/spectests/tests/spectest.rs | 1 + src/bin/wasmer.rs | 1 + 5 files changed, 214 insertions(+), 41 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 7a71a289fe2..1b9e5e7dd04 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -666,7 +666,11 @@ impl X64FunctionCode { a.emit_mov(Size::S64, src, Location::GPR(tmp_src)); src = Location::GPR(tmp_src); } - Location::Memory(_, _) | Location::GPR(_) => {} + Location::GPR(_) => { + a.emit_mov(Size::S64, src, Location::GPR(tmp_src)); + src = Location::GPR(tmp_src); + } + Location::Memory(_, _) => {} _ => unreachable!(), } @@ -2948,6 +2952,125 @@ impl FunctionCodeGenerator for X64FunctionCode { ret, ); } + Operator::I32Extend8S => { + let loc = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let ret = self.machine.acquire_locations( + a, + &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], + false, + )[0]; + self.value_stack.push(ret); + + let tmpg1 = self.machine.acquire_temp_gpr().unwrap(); + a.emit_mov(Size::S32, loc, Location::GPR(tmpg1)); + a.emit_and(Size::S32, Location::Imm32(0xFF), Location::GPR(tmpg1)); + Self::emit_relaxed_zx_sx( + a, + &mut self.machine, + Assembler::emit_movsx, + Size::S8, + Location::GPR(tmpg1), + Size::S32, + ret, + ); + self.machine.release_temp_gpr(tmpg1); + } + Operator::I32Extend16S => { + let loc = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let ret = self.machine.acquire_locations( + a, + &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], + false, + )[0]; + self.value_stack.push(ret); + + let tmpg1 = self.machine.acquire_temp_gpr().unwrap(); + a.emit_mov(Size::S32, loc, Location::GPR(tmpg1)); + a.emit_and(Size::S32, Location::Imm32(0xFFFF), Location::GPR(tmpg1)); + Self::emit_relaxed_zx_sx( + a, + &mut self.machine, + Assembler::emit_movsx, + Size::S16, + Location::GPR(tmpg1), + Size::S32, + ret, + ); + self.machine.release_temp_gpr(tmpg1); + } + Operator::I64Extend8S => { + let loc = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let ret = self.machine.acquire_locations( + a, + &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], + false, + )[0]; + self.value_stack.push(ret); + + let tmpg1 = self.machine.acquire_temp_gpr().unwrap(); + a.emit_mov(Size::S32, loc, Location::GPR(tmpg1)); + a.emit_and(Size::S32, Location::Imm32(0xFF), Location::GPR(tmpg1)); + Self::emit_relaxed_zx_sx( + a, + &mut self.machine, + Assembler::emit_movsx, + Size::S8, + Location::GPR(tmpg1), + Size::S64, + ret, + ); + self.machine.release_temp_gpr(tmpg1); + } + Operator::I64Extend16S => { + let loc = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let ret = self.machine.acquire_locations( + a, + &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], + false, + )[0]; + self.value_stack.push(ret); + + let tmpg1 = self.machine.acquire_temp_gpr().unwrap(); + a.emit_mov(Size::S32, loc, Location::GPR(tmpg1)); + a.emit_and(Size::S32, Location::Imm32(0xFFFF), Location::GPR(tmpg1)); + Self::emit_relaxed_zx_sx( + a, + &mut self.machine, + Assembler::emit_movsx, + Size::S16, + Location::GPR(tmpg1), + Size::S64, + ret, + ); + self.machine.release_temp_gpr(tmpg1); + } + Operator::I64Extend32S => { + let loc = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let ret = self.machine.acquire_locations( + a, + &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], + false, + )[0]; + self.value_stack.push(ret); + + let tmpg1 = self.machine.acquire_temp_gpr().unwrap(); + a.emit_mov(Size::S32, loc, Location::GPR(tmpg1)); + Self::emit_relaxed_zx_sx( + a, + &mut self.machine, + Assembler::emit_movsx, + Size::S32, + Location::GPR(tmpg1), + Size::S64, + ret, + ); + self.machine.release_temp_gpr(tmpg1); + } Operator::I32WrapI64 => { let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); diff --git a/lib/spectests/spectests/conversions.wast b/lib/spectests/spectests/conversions.wast index c0ae54a53b2..8022a1a6063 100644 --- a/lib/spectests/spectests/conversions.wast +++ b/lib/spectests/spectests/conversions.wast @@ -1,6 +1,11 @@ (module (func (export "i64.extend_i32_s") (param $x i32) (result i64) (i64.extend_i32_s (local.get $x))) (func (export "i64.extend_i32_u") (param $x i32) (result i64) (i64.extend_i32_u (local.get $x))) + (func (export "i64.extend32_s") (param $x i64) (result i64) (i64.extend32_s (local.get $x))) + (func (export "i64.extend16_s") (param $x i64) (result i64) (i64.extend16_s (local.get $x))) + (func (export "i64.extend8_s") (param $x i64) (result i64) (i64.extend8_s (local.get $x))) + (func (export "i32.extend16_s") (param $x i32) (result i32) (i32.extend16_s (local.get $x))) + (func (export "i32.extend8_s") (param $x i32) (result i32) (i32.extend8_s (local.get $x))) (func (export "i32.wrap_i64") (param $x i64) (result i32) (i32.wrap_i64 (local.get $x))) (func (export "i32.trunc_f32_s") (param $x f32) (result i32) (i32.trunc_f32_s (local.get $x))) (func (export "i32.trunc_f32_u") (param $x f32) (result i32) (i32.trunc_f32_u (local.get $x))) @@ -497,3 +502,46 @@ (assert_invalid (module (func (result f64) (f64.convert_i64_u (i32.const 0)))) "type mismatch") (assert_invalid (module (func (result f64) (f64.promote_f32 (i32.const 0)))) "type mismatch") (assert_invalid (module (func (result f64) (f64.reinterpret_i64 (i32.const 0)))) "type mismatch") + +(assert_return (invoke "i32.extend8_s" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "i32.extend8_s" (i32.const 0x7f)) (i32.const 127)) +(assert_return (invoke "i32.extend8_s" (i32.const 0x80)) (i32.const -128)) +(assert_return (invoke "i32.extend8_s" (i32.const 0xff)) (i32.const -1)) +(assert_return (invoke "i32.extend8_s" (i32.const 0x012345_00)) (i32.const 0)) +(assert_return (invoke "i32.extend8_s" (i32.const 0xfedcba_80)) (i32.const -0x80)) +(assert_return (invoke "i32.extend8_s" (i32.const -1)) (i32.const -1)) + +(assert_return (invoke "i32.extend16_s" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "i32.extend16_s" (i32.const 0x7fff)) (i32.const 32767)) +(assert_return (invoke "i32.extend16_s" (i32.const 0x8000)) (i32.const -32768)) +(assert_return (invoke "i32.extend16_s" (i32.const 0xffff)) (i32.const -1)) +(assert_return (invoke "i32.extend16_s" (i32.const 0x0123_0000)) (i32.const 0)) +(assert_return (invoke "i32.extend16_s" (i32.const 0xfedc_8000)) (i32.const -0x8000)) +(assert_return (invoke "i32.extend16_s" (i32.const -1)) (i32.const -1)) + +(assert_return (invoke "i64.extend8_s" (i64.const 0)) (i64.const 0)) +(assert_return (invoke "i64.extend8_s" (i64.const 0x7f)) (i64.const 127)) +(assert_return (invoke "i64.extend8_s" (i64.const 0x80)) (i64.const -128)) +(assert_return (invoke "i64.extend8_s" (i64.const 0xff)) (i64.const -1)) +(assert_return (invoke "i64.extend8_s" (i64.const 0x01234567_89abcd_00)) (i64.const 0)) +(assert_return (invoke "i64.extend8_s" (i64.const 0xfedcba98_765432_80)) (i64.const -0x80)) +(assert_return (invoke "i64.extend8_s" (i64.const -1)) (i64.const -1)) + +(assert_return (invoke "i64.extend16_s" (i64.const 0)) (i64.const 0)) +(assert_return (invoke "i64.extend16_s" (i64.const 0x7fff)) (i64.const 32767)) +(assert_return (invoke "i64.extend16_s" (i64.const 0x8000)) (i64.const -32768)) +(assert_return (invoke "i64.extend16_s" (i64.const 0xffff)) (i64.const -1)) +(assert_return (invoke "i64.extend16_s" (i64.const 0x12345678_9abc_0000)) (i64.const 0)) +(assert_return (invoke "i64.extend16_s" (i64.const 0xfedcba98_7654_8000)) (i64.const -0x8000)) +(assert_return (invoke "i64.extend16_s" (i64.const -1)) (i64.const -1)) + +(assert_return (invoke "i64.extend32_s" (i64.const 0)) (i64.const 0)) +(assert_return (invoke "i64.extend32_s" (i64.const 0x7fff)) (i64.const 32767)) +(assert_return (invoke "i64.extend32_s" (i64.const 0x8000)) (i64.const 32768)) +(assert_return (invoke "i64.extend32_s" (i64.const 0xffff)) (i64.const 65535)) +(assert_return (invoke "i64.extend32_s" (i64.const 0x7fffffff)) (i64.const 0x7fffffff)) +(assert_return (invoke "i64.extend32_s" (i64.const 0x80000000)) (i64.const -0x80000000)) +(assert_return (invoke "i64.extend32_s" (i64.const 0xffffffff)) (i64.const -1)) +(assert_return (invoke "i64.extend32_s" (i64.const 0x01234567_00000000)) (i64.const 0)) +(assert_return (invoke "i64.extend32_s" (i64.const 0xfedcba98_80000000)) (i64.const -0x80000000)) +(assert_return (invoke "i64.extend32_s" (i64.const -1)) (i64.const -1)) \ No newline at end of file diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index c7776693908..62802769383 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -396,73 +396,73 @@ singlepass:fail:call_indirect.wast:493 # AssertTrap - expected trap, got Runtime singlepass:fail:call_indirect.wast:494 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:call_indirect.wast:500 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:call_indirect.wast:501 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:70 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:71 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:72 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:73 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:74 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:75 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:76 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:77 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:92 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:93 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:94 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:95 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:96 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:78 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:79 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:80 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:81 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:82 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:97 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:98 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:99 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:115 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:116 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:117 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:118 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:119 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:100 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:101 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:102 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:103 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:104 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:120 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:121 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:122 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:138 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:139 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:140 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:141 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:142 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:123 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:124 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:125 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:126 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:127 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:143 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:144 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:145 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:146 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:147 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:148 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:166 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:167 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:168 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:169 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:170 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:149 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:150 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:151 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:152 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:153 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:171 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:172 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:173 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:186 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:187 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:188 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:189 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:190 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:174 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:175 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:176 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:177 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:178 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:191 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:192 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:193 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:211 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:212 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:213 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:214 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:215 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:194 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:195 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:196 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:197 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:198 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:216 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:217 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:218 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:235 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:236 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:237 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:238 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:conversions.wast:239 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:219 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:220 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:221 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:222 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:223 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:240 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:241 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:242 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:243 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:244 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:245 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:246 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:conversions.wast:247 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:elem.wast:353 # AssertTrap - expected trap, got Runtime:Error unknown error 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 diff --git a/lib/spectests/tests/spectest.rs b/lib/spectests/tests/spectest.rs index 19114ff6783..299971ee154 100644 --- a/lib/spectests/tests/spectest.rs +++ b/lib/spectests/tests/spectest.rs @@ -186,6 +186,7 @@ mod tests { let mut features = wabt::Features::new(); features.enable_simd(); features.enable_threads(); + features.enable_sign_extension(); let mut parser: ScriptParser = ScriptParser::from_source_and_name_with_features(&source, filename, features) .expect(&format!("Failed to parse script {}", &filename)); diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 7af5df3e258..74f3ef4700f 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -394,6 +394,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { if !utils::is_wasm_binary(&wasm_binary) { let mut features = wabt::Features::new(); + features.enable_sign_extension(); if options.features.simd || options.features.all { features.enable_simd(); } From b36bf011884f664ed12f33e4563d28329d743783 Mon Sep 17 00:00:00 2001 From: losfair Date: Sun, 17 Nov 2019 04:38:40 +0800 Subject: [PATCH 156/342] Update Rust version to 1.39.0. --- Dockerfile | 2 +- README.md | 2 +- azure-pipelines.yml | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6affe470faf..c118f0f5752 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM circleci/rust:1.38.0-stretch as wasmer-build-env +FROM circleci/rust:1.39.0-stretch as wasmer-build-env RUN sudo apt-get update && \ sudo apt-get install -y --no-install-recommends \ cmake \ diff --git a/README.md b/README.md index 98533edf91b..77fd3435744 100644 --- a/README.md +++ b/README.md @@ -181,7 +181,7 @@ nginx and Lua do not work on Windows - you can track the progress on [this issue ## Building -[![Rustc Version 1.38+](https://img.shields.io/badge/rustc-1.37+-red.svg?style=flat-square)](https://blog.rust-lang.org/2019/09/26/Rust-1.38.0.html) +[![Rustc Version 1.39+](https://img.shields.io/badge/rustc-1.39+-red.svg?style=flat-square)](https://blog.rust-lang.org/2019/09/26/Rust-1.39.0.html) Wasmer is built with [Cargo](https://crates.io/), the Rust package manager. diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a8b571e28a0..d99561a2156 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -22,7 +22,7 @@ jobs: - script: cargo fmt --all -- --check displayName: Lint variables: - rust_toolchain: '1.38.0' + rust_toolchain: '1.39.0' - job: Test strategy: @@ -39,7 +39,7 @@ jobs: CARGO_HTTP_CHECK_REVOKE: false windows: imageName: "vs2017-win2016" - rust_toolchain: '1.38.0' + rust_toolchain: '1.39.0' pool: vmImage: $(imageName) condition: in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying') @@ -100,7 +100,7 @@ jobs: MACOSX_DEPLOYMENT_TARGET: 10.10 windows: imageName: "vs2017-win2016" - rust_toolchain: '1.38.0' + rust_toolchain: '1.39.0' # RUSTFLAGS: -Ctarget-feature=+crt-static pool: vmImage: $(imageName) @@ -163,7 +163,7 @@ jobs: MACOSX_DEPLOYMENT_TARGET: 10.10 windows: imageName: "vs2017-win2016" - rust_toolchain: '1.38.0' + rust_toolchain: '1.39.0' # RUSTFLAGS: -Ctarget-feature=+crt-static pool: vmImage: $(imageName) From 021a75244e52ec420bd6db65849b163e1673990c Mon Sep 17 00:00:00 2001 From: losfair Date: Sun, 17 Nov 2019 04:39:39 +0800 Subject: [PATCH 157/342] Reformat code for rust 1.39. --- lib/singlepass-backend/src/emitter_x64.rs | 88 +++++++++++++++++------ 1 file changed, 66 insertions(+), 22 deletions(-) diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index a40d5b5e5f0..251868231f1 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -709,14 +709,18 @@ impl Emitter for Assembler { match (sz, src) { (Size::S64, Location::Imm32(src)) => dynasm!(self ; push src as i32), (Size::S64, Location::GPR(src)) => dynasm!(self ; push Rq(src as u8)), - (Size::S64, Location::Memory(src, disp)) => dynasm!(self ; push QWORD [Rq(src as u8) + disp]), + (Size::S64, Location::Memory(src, disp)) => { + dynasm!(self ; push QWORD [Rq(src as u8) + disp]) + } _ => panic!("singlepass can't emit PUSH {:?} {:?}", sz, src), } } fn emit_pop(&mut self, sz: Size, dst: Location) { match (sz, dst) { (Size::S64, Location::GPR(dst)) => dynasm!(self ; pop Rq(dst as u8)), - (Size::S64, Location::Memory(dst, disp)) => dynasm!(self ; pop QWORD [Rq(dst as u8) + disp]), + (Size::S64, Location::Memory(dst, disp)) => { + dynasm!(self ; pop QWORD [Rq(dst as u8) + disp]) + } _ => panic!("singlepass can't emit POP {:?} {:?}", sz, dst), } } @@ -738,13 +742,21 @@ impl Emitter for Assembler { fn emit_neg(&mut self, sz: Size, value: Location) { match (sz, value) { (Size::S8, Location::GPR(value)) => dynasm!(self ; neg Rb(value as u8)), - (Size::S8, Location::Memory(value, disp)) => dynasm!(self ; neg [Rq(value as u8) + disp]), + (Size::S8, Location::Memory(value, disp)) => { + dynasm!(self ; neg [Rq(value as u8) + disp]) + } (Size::S16, Location::GPR(value)) => dynasm!(self ; neg Rw(value as u8)), - (Size::S16, Location::Memory(value, disp)) => dynasm!(self ; neg [Rq(value as u8) + disp]), + (Size::S16, Location::Memory(value, disp)) => { + dynasm!(self ; neg [Rq(value as u8) + disp]) + } (Size::S32, Location::GPR(value)) => dynasm!(self ; neg Rd(value as u8)), - (Size::S32, Location::Memory(value, disp)) => dynasm!(self ; neg [Rq(value as u8) + disp]), + (Size::S32, Location::Memory(value, disp)) => { + dynasm!(self ; neg [Rq(value as u8) + disp]) + } (Size::S64, Location::GPR(value)) => dynasm!(self ; neg Rq(value as u8)), - (Size::S64, Location::Memory(value, disp)) => dynasm!(self ; neg [Rq(value as u8) + disp]), + (Size::S64, Location::Memory(value, disp)) => { + dynasm!(self ; neg [Rq(value as u8) + disp]) + } _ => panic!("singlepass can't emit NEG {:?} {:?}", sz, value), } } @@ -997,18 +1009,30 @@ 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), }; } 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)), + (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), }; } @@ -1080,57 +1104,77 @@ 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)) + } } } 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)), + 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)), - XMMOrMemory::Memory(base, disp) => dynasm!(self ; ucomiss Rx(dst as u8), [Rq(base as u8) + disp]), + XMMOrMemory::Memory(base, disp) => { + dynasm!(self ; ucomiss Rx(dst as u8), [Rq(base as u8) + disp]) + } } } fn emit_ucomisd(&mut self, src: XMMOrMemory, dst: XMM) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; ucomisd Rx(dst as u8), Rx(x as u8)), - XMMOrMemory::Memory(base, disp) => dynasm!(self ; ucomisd Rx(dst as u8), [Rq(base as u8) + disp]), + XMMOrMemory::Memory(base, disp) => { + dynasm!(self ; ucomisd Rx(dst as u8), [Rq(base as u8) + disp]) + } } } fn emit_cvttss2si_32(&mut self, src: XMMOrMemory, dst: GPR) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; cvttss2si Rd(dst as u8), Rx(x as u8)), - XMMOrMemory::Memory(base, disp) => dynasm!(self ; cvttss2si Rd(dst as u8), [Rq(base as u8) + disp]), + XMMOrMemory::Memory(base, disp) => { + dynasm!(self ; cvttss2si Rd(dst as u8), [Rq(base as u8) + disp]) + } } } fn emit_cvttss2si_64(&mut self, src: XMMOrMemory, dst: GPR) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; cvttss2si Rq(dst as u8), Rx(x as u8)), - XMMOrMemory::Memory(base, disp) => dynasm!(self ; cvttss2si Rq(dst as u8), [Rq(base as u8) + disp]), + XMMOrMemory::Memory(base, disp) => { + dynasm!(self ; cvttss2si Rq(dst as u8), [Rq(base as u8) + disp]) + } } } fn emit_cvttsd2si_32(&mut self, src: XMMOrMemory, dst: GPR) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; cvttsd2si Rd(dst as u8), Rx(x as u8)), - XMMOrMemory::Memory(base, disp) => dynasm!(self ; cvttsd2si Rd(dst as u8), [Rq(base as u8) + disp]), + XMMOrMemory::Memory(base, disp) => { + dynasm!(self ; cvttsd2si Rd(dst as u8), [Rq(base as u8) + disp]) + } } } fn emit_cvttsd2si_64(&mut self, src: XMMOrMemory, dst: GPR) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; cvttsd2si Rq(dst as u8), Rx(x as u8)), - XMMOrMemory::Memory(base, disp) => dynasm!(self ; cvttsd2si Rq(dst as u8), [Rq(base as u8) + disp]), + XMMOrMemory::Memory(base, disp) => { + dynasm!(self ; cvttsd2si Rq(dst as u8), [Rq(base as u8) + disp]) + } } } From 08beb99baa5ea339110ef87cffbeae106238456d Mon Sep 17 00:00:00 2001 From: losfair Date: Sun, 17 Nov 2019 05:15:10 +0800 Subject: [PATCH 158/342] Fix popcnt. --- lib/singlepass-backend/src/translator_aarch64.rs | 15 +++++++++++---- src/bin/wasmer.rs | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 2eedb2072d6..3a4d3ded1d2 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -1248,9 +1248,12 @@ impl Emitter for Assembler { self ; mov v_tmp1.S[0], w_tmp1 ; cnt v_tmp1.B16, v_tmp1.B16 - ; mov W(map_gpr(dst).x()), v_tmp1.S[0] - ; add W(map_gpr(dst).x()), W(map_gpr(dst).x()), W(map_gpr(dst).x()), lsr 16 - ; and W(map_gpr(dst).x()), W(map_gpr(dst).x()), 31 + ; mov w_tmp1, v_tmp1.S[0] + ; mov W(map_gpr(dst).x()), w_tmp1 + ; add W(map_gpr(dst).x()), W(map_gpr(dst).x()), w_tmp1, lsr 8 + ; add W(map_gpr(dst).x()), W(map_gpr(dst).x()), w_tmp1, lsr 16 + ; add W(map_gpr(dst).x()), W(map_gpr(dst).x()), w_tmp1, lsr 24 + ; and W(map_gpr(dst).x()), W(map_gpr(dst).x()), 255 ); } _ => unreachable!(), @@ -1283,10 +1286,14 @@ impl Emitter for Assembler { ; cnt v_tmp1.B16, v_tmp1.B16 ; mov x_tmp1, v_tmp1.D[0] ; mov X(map_gpr(dst).x()), x_tmp1 + ; add X(map_gpr(dst).x()), X(map_gpr(dst).x()), x_tmp1, lsr 8 ; add X(map_gpr(dst).x()), X(map_gpr(dst).x()), x_tmp1, lsr 16 + ; add X(map_gpr(dst).x()), X(map_gpr(dst).x()), x_tmp1, lsr 24 ; add X(map_gpr(dst).x()), X(map_gpr(dst).x()), x_tmp1, lsr 32 + ; add X(map_gpr(dst).x()), X(map_gpr(dst).x()), x_tmp1, lsr 40 ; add X(map_gpr(dst).x()), X(map_gpr(dst).x()), x_tmp1, lsr 48 - ; and X(map_gpr(dst).x()), X(map_gpr(dst).x()), 63 + ; add X(map_gpr(dst).x()), X(map_gpr(dst).x()), x_tmp1, lsr 56 + ; and X(map_gpr(dst).x()), X(map_gpr(dst).x()), 255 ); } _ => unreachable!(), diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 340669f68eb..5c308f42dda 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -723,7 +723,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { Some(fun) => fun, _ => "main", }; - instance + let result = instance .dyn_func(&invoke_fn) .map_err(|e| format!("{:?}", e))? .call(&args) From cbaa94a7fa30a409d95ba2caf1549e9bbe42380f Mon Sep 17 00:00:00 2001 From: losfair Date: Mon, 18 Nov 2019 01:08:39 +0800 Subject: [PATCH 159/342] Fix movsx(S32, S64). --- lib/singlepass-backend/src/translator_aarch64.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 3a4d3ded1d2..7070eea4e24 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -1384,7 +1384,7 @@ impl Emitter for Assembler { } else { dynasm!(self ; b >after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, unreachable!(), } From 5d2ee4fcc84fdd4d94b49488bf8857746c777633 Mon Sep 17 00:00:00 2001 From: losfair Date: Mon, 18 Nov 2019 01:39:44 +0800 Subject: [PATCH 160/342] Fix floating point comparision involving NaNs. --- lib/singlepass-backend/src/codegen_x64.rs | 5 +- .../src/translator_aarch64.rs | 70 +++++++------------ 2 files changed, 30 insertions(+), 45 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index c0621796432..63d08ecff5f 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -1336,7 +1336,10 @@ impl X64FunctionCode { value_stack.push(ret); Self::emit_relaxed_avx(a, m, f, loc_a, loc_b, ret); - a.emit_and(Size::S32, Location::Imm32(1), ret); // FIXME: Why? + + // Workaround for behavior inconsistency among different backing implementations. + // (all bits or only the least significant bit are set to one?) + a.emit_and(Size::S32, Location::Imm32(1), ret); } /// Floating point (AVX) binary operation with both operands popped from the virtual stack. diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 7070eea4e24..d6361fc1aa3 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -408,39 +408,18 @@ macro_rules! avx_fn { } } -macro_rules! avx_fn_bitwise_inv { - ($ins:ident, $width:ident, $width_int:ident, $name:ident) => { +macro_rules! avx_cmp { + ($cmpty:tt, $width:ident, $width_int:ident, $name:ident) => { fn $name(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { match src2 { - XMMOrMemory::XMM(src2) => dynasm!(self ; $ins $width(map_xmm(dst).v()), $width(map_xmm(src1).v()), $width(map_xmm(src2).v())), - XMMOrMemory::Memory(base, disp) => { - if disp >= 0 { - dynasm!(self ; b >after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, { + dynasm!( + self + ; fcmpe $width(map_xmm(src1).v()), $width(map_xmm(src2).v()) + ; cset w_tmp1, $cmpty + ; mov V(map_xmm(dst).v()).$width[0], $width_int(X_TMP1) ); - } - } - dynasm!(self - ; mov $width_int(X_TMP1), V(map_xmm(dst).v()).$width[0] - ; mvn $width_int(X_TMP1), $width_int(X_TMP1) - ; mov V(map_xmm(dst).v()).$width[0], $width_int(X_TMP1) - ); - } - } -} - -macro_rules! avx_fn_reversed { - ($ins:ident, $width:ident, $width_int:ident, $name:ident) => { - fn $name(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { - match src2 { - XMMOrMemory::XMM(src2) => dynasm!(self ; $ins $width(map_xmm(dst).v()), $width(map_xmm(src2).v()), $width(map_xmm(src1).v())), + }, XMMOrMemory::Memory(base, disp) => { if disp >= 0 { dynasm!(self ; b >after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, a lt b - avx_fn!(fcmge, S, W, emit_vcmpgess); - avx_fn_bitwise_inv!(fcmgt, S, W, emit_vcmpless); // a not gt b <=> a le b - avx_fn!(fcmeq, S, W, emit_vcmpeqss); - avx_fn_bitwise_inv!(fcmeq, S, W, emit_vcmpneqss); // a not eq b <=> a neq b + avx_cmp!(gt, S, W, emit_vcmpgtss); + avx_cmp!(ge, S, W, emit_vcmpgess); + avx_cmp!(mi, S, W, emit_vcmpltss); + avx_cmp!(ls, S, W, emit_vcmpless); + avx_cmp!(eq, S, W, emit_vcmpeqss); + avx_cmp!(ne, S, W, emit_vcmpneqss); avx_fn_unop!(fsqrt, S, emit_vsqrtss); avx_fn_unop!(frintn, S, emit_vroundss_nearest); // to nearest with ties to even avx_fn_unop!(frintm, S, emit_vroundss_floor); // toward minus infinity @@ -1457,12 +1439,12 @@ impl Emitter for Assembler { avx_fn!(fdiv, D, X, emit_vdivsd); avx_fn!(fmax, D, X, emit_vmaxsd); avx_fn!(fmin, D, X, emit_vminsd); - avx_fn!(fcmgt, D, X, emit_vcmpgtsd); - avx_fn_reversed!(fcmgt, D, X, emit_vcmpltsd); // b gt a <=> a lt b - avx_fn!(fcmge, D, X, emit_vcmpgesd); - avx_fn_bitwise_inv!(fcmgt, D, X, emit_vcmplesd); // a not gt b <=> a le b - avx_fn!(fcmeq, D, X, emit_vcmpeqsd); - avx_fn_bitwise_inv!(fcmeq, D, X, emit_vcmpneqsd); // a not eq b <=> a neq b + avx_cmp!(gt, D, X, emit_vcmpgtsd); + avx_cmp!(ge, D, X, emit_vcmpgesd); + avx_cmp!(mi, D, X, emit_vcmpltsd); + avx_cmp!(ls, D, X, emit_vcmplesd); + avx_cmp!(eq, D, X, emit_vcmpeqsd); + avx_cmp!(ne, D, X, emit_vcmpneqsd); avx_fn_unop!(fsqrt, D, emit_vsqrtsd); avx_fn_unop!(frintn, D, emit_vroundsd_nearest); // to nearest with ties to even avx_fn_unop!(frintm, D, emit_vroundsd_floor); // toward minus infinity From 1eed6ce8f8017eb905ede6b3df1bc62d2559d3f3 Mon Sep 17 00:00:00 2001 From: losfair Date: Mon, 18 Nov 2019 02:06:31 +0800 Subject: [PATCH 161/342] Fix CONSTRUCT_STACK_AND_CALL_WASM for aarch64. --- lib/singlepass-backend/src/codegen_x64.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 63d08ecff5f..58ca6a11147 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -206,9 +206,9 @@ lazy_static! { ; end_copy_params: // return address - ; adr x9, >done + ; adr x20, >done ; sub x28, x28, 8 - ; str x9, [x28] // Keep this consistent with RSP mapping in translator_aarch64 + ; str x20, [x28] // Keep this consistent with RSP mapping in translator_aarch64 // Jump to target function! ; br x3 From 4e42fa1e48cdc641fb4989e9cdd20aa2b8d36ee0 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 18 Nov 2019 12:22:17 +0100 Subject: [PATCH 162/342] fix(runtime-core) Remove unnecessary implementation of `WasmTypeList`. The unit tests `test_func_arity_*` covers all possibilities, from 0 to 12. Removing this specific implementation of `WasmTypeList` for `(A,)` doesn't break the test cases. Also, the `impl_traits!` macro already implement `WasmTypeList` for `(A,)` with `impl_traits!([transparent] S1, A)`. It's not clear why `rustc` doesn't detect that though. --- lib/runtime-core/src/typed_func.rs | 81 ------------------------------ 1 file changed, 81 deletions(-) diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index d2fe59a617d..895af819f64 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -343,87 +343,6 @@ impl WasmTypeList for Infallible { } } -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( - self, - f: NonNull, - wasm: Wasm, - ctx: *mut vm::Ctx, - ) -> Result - where - Rets: WasmTypeList, - { - let (a,) = self; - let args = [a.to_native().to_binary()]; - let mut rets = Rets::empty_ret_array(); - 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, - ) { - Ok(Rets::from_ret_array(rets)) - } else { - if let Some(data) = user_error { - Err(RuntimeError::Error { data }) - } else { - Err(RuntimeError::Trap { - msg: trap.to_string().into(), - }) - } - } - } -} - -impl<'a, A: WasmExternType, Rets> Func<'a, (A,), Rets, Wasm> -where - Rets: WasmTypeList, -{ - /// Call wasm function and return results. - pub fn call(&self, a: A) -> Result { - unsafe { ::call(a, self.func, self.inner, self.vmctx) } - } -} - macro_rules! impl_traits { ( [$repr:ident] $struct_name:ident, $( $x:ident ),* ) => { /// Struct for typed funcs. From 85a53e8e1fa4974224ff5c8cbf21ddb5796403bc Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 18 Nov 2019 12:44:00 +0100 Subject: [PATCH 163/342] test(runtime-core) Test closures in `Func::new`. --- lib/runtime-core/src/typed_func.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index d2fe59a617d..87003612e3b 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -819,8 +819,14 @@ mod tests { vec![$($x),*].iter().sum() } - let _func = Func::new(with_vmctx); - let _func = Func::new(without_vmctx); + let _ = Func::new(with_vmctx); + let _ = Func::new(without_vmctx); + let _ = Func::new(|_: &mut vm::Ctx, $($x: i32),*| -> i32 { + vec![$($x),*].iter().sum() + }); + let _ = Func::new(|$($x: i32),*| -> i32 { + vec![$($x),*].iter().sum() + }); } } } @@ -837,6 +843,8 @@ mod tests { let _ = Func::new(foo); let _ = Func::new(bar); + let _ = Func::new(|_: &mut vm::Ctx| -> i32 { 0 }); + let _ = Func::new(|| -> i32 { 0 }); } test_func_arity_n!(test_func_arity_1, a); From f6cb6ce286c161871aed9d0edcd055600f82fccf Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 18 Nov 2019 12:44:40 +0100 Subject: [PATCH 164/342] fix(runtime-core) Remove a warning for `unused_parens`. The behavior of `unused_parens` has changed since Rust 1.39. A warning is then raised. This patch fixes that. --- lib/runtime-core/src/typed_func.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 87003612e3b..a3a22720327 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -458,8 +458,8 @@ macro_rules! impl_traits { ( $( WasmExternType::from_native($x) ),* ) } + #[allow(unused_parens, non_snake_case)] fn into_c_struct(self) -> Self::CStruct { - #[allow(unused_parens, non_snake_case)] let ( $( $x ),* ) = self; $struct_name ( $( WasmExternType::to_native($x) ),* ) @@ -469,7 +469,7 @@ macro_rules! impl_traits { &[$( $x::Native::TYPE ),*] } - #[allow(non_snake_case)] + #[allow(unused_parens, non_snake_case)] unsafe fn call( self, f: NonNull, @@ -479,7 +479,6 @@ macro_rules! impl_traits { where Rets: WasmTypeList { - #[allow(unused_parens)] let ( $( $x ),* ) = self; let args = [ $( $x.to_native().to_binary()),* ]; let mut rets = Rets::empty_ret_array(); From 23f03f555b321aed1d09542501063996ab0d9c83 Mon Sep 17 00:00:00 2001 From: losfair Date: Mon, 18 Nov 2019 23:10:49 +0800 Subject: [PATCH 165/342] Fix compilation failure in tiering.rs. --- lib/runtime-core/src/tiering.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime-core/src/tiering.rs b/lib/runtime-core/src/tiering.rs index c5e52107b2d..7d2a27d874e 100644 --- a/lib/runtime-core/src/tiering.rs +++ b/lib/runtime-core/src/tiering.rs @@ -1,6 +1,6 @@ //! The tiering module supports switching between code compiled with different optimization levels //! as runtime. -use crate::backend::{Compiler, CompilerConfig}; +use crate::backend::{Backend, Compiler, CompilerConfig}; use crate::compile_with_config; use crate::fault::{ catch_unsafe_unwind, ensure_sighandler, pop_code_version, push_code_version, with_ctx, From d7308c361d8fdea44d0420e924aa5ba37b60b34e Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 19 Nov 2019 01:25:01 +0800 Subject: [PATCH 166/342] Fix call_indirect on imported functions. --- lib/singlepass-backend/src/codegen_x64.rs | 23 ++++-- lib/singlepass-backend/src/emitter_x64.rs | 11 +++ .../src/translator_aarch64.rs | 72 +++++++++++++++++++ 3 files changed, 100 insertions(+), 6 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 58ca6a11147..cd2a729cb14 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -472,12 +472,15 @@ impl ModuleCodeGenerator for X64ModuleCodeGenerator { fn new() -> X64ModuleCodeGenerator { + let mut a = Assembler::new().unwrap(); + a.notify_begin(); + X64ModuleCodeGenerator { functions: vec![], signatures: None, function_signatures: None, function_labels: Some(HashMap::new()), - assembler: Some(Assembler::new().unwrap()), + assembler: Some(a), func_import_count: 0, config: None, } @@ -556,7 +559,7 @@ impl ModuleCodeGenerator mut self, _: &ModuleInfo, ) -> Result<(X64ExecutionContext, Box), CodegenError> { - let (assembler, function_labels, breakpoints) = match self.functions.last_mut() { + let (mut assembler, function_labels, breakpoints) = match self.functions.last_mut() { Some(x) => ( x.assembler.take().unwrap(), x.function_labels.take().unwrap(), @@ -569,6 +572,7 @@ impl ModuleCodeGenerator ), }; + assembler.notify_end(); let total_size = assembler.get_offset().0; let _output = assembler.finalize().unwrap(); let mut output = CodeMemory::new(_output.len()); @@ -5139,10 +5143,17 @@ impl FunctionCodeGenerator for X64FunctionCode { a, &mut self.machine, |a| { - a.emit_call_location(Location::Memory( - GPR::RAX, - (vm::Anyfunc::offset_func() as usize) as i32, - )); + if a.arch_requires_indirect_call_trampoline() { + a.arch_emit_indirect_call_with_trampoline(Location::Memory( + GPR::RAX, + (vm::Anyfunc::offset_func() as usize) as i32, + )); + } else { + a.emit_call_location(Location::Memory( + GPR::RAX, + (vm::Anyfunc::offset_func() as usize) as i32, + )); + } }, params.iter().map(|x| *x), Some((&mut self.fsm, &mut self.control_stack)), diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index f426b6d0274..5a78554359d 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -271,6 +271,17 @@ pub trait Emitter { fn arch_supports_canonicalize_nan(&self) -> bool { true } + + fn arch_requires_indirect_call_trampoline(&self) -> bool { + false + } + + fn arch_emit_indirect_call_with_trampoline(&mut self, _loc: Location) { + unimplemented!() + } + + fn notify_begin(&mut self) {} + fn notify_end(&mut self) {} } fn _dummy(a: &mut Assembler) { diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index d6361fc1aa3..a26e2073b3e 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -1702,6 +1702,78 @@ impl Emitter for Assembler { fn arch_supports_canonicalize_nan(&self) -> bool { false } + + fn arch_requires_indirect_call_trampoline(&self) -> bool { + true + } + + fn arch_emit_indirect_call_with_trampoline(&mut self, loc: Location) { + match loc { + Location::GPR(x) => { + dynasm!(self + // Push return address. + ; sub x_rsp, x_rsp, 8 + ; adr x_tmp1, >done + ; str x_tmp1, [x_rsp] + ); + dynasm!(self + ; adr x_tmp1, >program_end + ; cmp X(map_gpr(x).x()), x_tmp1 + ; b.ge >external + ; adr x_tmp1, external + ; br X(map_gpr(x).x()) + ; external: + ); + self.emit_homomorphic_host_redirection(x); + dynasm!(self ; done: ); + } + Location::Memory(base, disp) => { + if disp >= 0 { + dynasm!(self ; b >after ; disp: ; .dword disp ; after: ; ldr w_tmp3, after ; disp: ; .dword -disp ; after: ; ldr w_tmp3, done + ; str x_tmp1, [x_rsp] + + // Read memory. + ; ldr X(map_gpr(GPR::RAX).x()), [x_tmp3] + ); + dynasm!(self + ; adr x_tmp1, >program_end + ; cmp X(map_gpr(GPR::RAX).x()), x_tmp1 + ; b.ge >external + ; adr x_tmp1, external + ; br X(map_gpr(GPR::RAX).x()) + ; external: + ); + self.emit_homomorphic_host_redirection(GPR::RAX); + dynasm!(self ; done: ); + } + _ => unreachable!(), + } + } + + fn notify_begin(&mut self) { + dynasm!( + self + ; program_begin: + ); + } + + fn notify_end(&mut self) { + dynasm!( + self + ; program_end: + ); + } } fn emit_clz_variant( From 2cbc7481880d4fefe8474beaf210727dd7391c4a Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 18 Nov 2019 09:59:07 -0800 Subject: [PATCH 167/342] Revert "Update Rust version to 1.39.0." --- Dockerfile | 2 +- README.md | 2 +- azure-pipelines.yml | 8 +-- lib/singlepass-backend/src/emitter_x64.rs | 88 ++++++----------------- 4 files changed, 28 insertions(+), 72 deletions(-) diff --git a/Dockerfile b/Dockerfile index c118f0f5752..6affe470faf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM circleci/rust:1.39.0-stretch as wasmer-build-env +FROM circleci/rust:1.38.0-stretch as wasmer-build-env RUN sudo apt-get update && \ sudo apt-get install -y --no-install-recommends \ cmake \ diff --git a/README.md b/README.md index 77fd3435744..98533edf91b 100644 --- a/README.md +++ b/README.md @@ -181,7 +181,7 @@ nginx and Lua do not work on Windows - you can track the progress on [this issue ## Building -[![Rustc Version 1.39+](https://img.shields.io/badge/rustc-1.39+-red.svg?style=flat-square)](https://blog.rust-lang.org/2019/09/26/Rust-1.39.0.html) +[![Rustc Version 1.38+](https://img.shields.io/badge/rustc-1.37+-red.svg?style=flat-square)](https://blog.rust-lang.org/2019/09/26/Rust-1.38.0.html) Wasmer is built with [Cargo](https://crates.io/), the Rust package manager. diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d99561a2156..a8b571e28a0 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -22,7 +22,7 @@ jobs: - script: cargo fmt --all -- --check displayName: Lint variables: - rust_toolchain: '1.39.0' + rust_toolchain: '1.38.0' - job: Test strategy: @@ -39,7 +39,7 @@ jobs: CARGO_HTTP_CHECK_REVOKE: false windows: imageName: "vs2017-win2016" - rust_toolchain: '1.39.0' + rust_toolchain: '1.38.0' pool: vmImage: $(imageName) condition: in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying') @@ -100,7 +100,7 @@ jobs: MACOSX_DEPLOYMENT_TARGET: 10.10 windows: imageName: "vs2017-win2016" - rust_toolchain: '1.39.0' + rust_toolchain: '1.38.0' # RUSTFLAGS: -Ctarget-feature=+crt-static pool: vmImage: $(imageName) @@ -163,7 +163,7 @@ jobs: MACOSX_DEPLOYMENT_TARGET: 10.10 windows: imageName: "vs2017-win2016" - rust_toolchain: '1.39.0' + rust_toolchain: '1.38.0' # RUSTFLAGS: -Ctarget-feature=+crt-static pool: vmImage: $(imageName) diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index 251868231f1..a40d5b5e5f0 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -709,18 +709,14 @@ impl Emitter for Assembler { match (sz, src) { (Size::S64, Location::Imm32(src)) => dynasm!(self ; push src as i32), (Size::S64, Location::GPR(src)) => dynasm!(self ; push Rq(src as u8)), - (Size::S64, Location::Memory(src, disp)) => { - dynasm!(self ; push QWORD [Rq(src as u8) + disp]) - } + (Size::S64, Location::Memory(src, disp)) => dynasm!(self ; push QWORD [Rq(src as u8) + disp]), _ => panic!("singlepass can't emit PUSH {:?} {:?}", sz, src), } } fn emit_pop(&mut self, sz: Size, dst: Location) { match (sz, dst) { (Size::S64, Location::GPR(dst)) => dynasm!(self ; pop Rq(dst as u8)), - (Size::S64, Location::Memory(dst, disp)) => { - dynasm!(self ; pop QWORD [Rq(dst as u8) + disp]) - } + (Size::S64, Location::Memory(dst, disp)) => dynasm!(self ; pop QWORD [Rq(dst as u8) + disp]), _ => panic!("singlepass can't emit POP {:?} {:?}", sz, dst), } } @@ -742,21 +738,13 @@ impl Emitter for Assembler { fn emit_neg(&mut self, sz: Size, value: Location) { match (sz, value) { (Size::S8, Location::GPR(value)) => dynasm!(self ; neg Rb(value as u8)), - (Size::S8, Location::Memory(value, disp)) => { - dynasm!(self ; neg [Rq(value as u8) + disp]) - } + (Size::S8, Location::Memory(value, disp)) => dynasm!(self ; neg [Rq(value as u8) + disp]), (Size::S16, Location::GPR(value)) => dynasm!(self ; neg Rw(value as u8)), - (Size::S16, Location::Memory(value, disp)) => { - dynasm!(self ; neg [Rq(value as u8) + disp]) - } + (Size::S16, Location::Memory(value, disp)) => dynasm!(self ; neg [Rq(value as u8) + disp]), (Size::S32, Location::GPR(value)) => dynasm!(self ; neg Rd(value as u8)), - (Size::S32, Location::Memory(value, disp)) => { - dynasm!(self ; neg [Rq(value as u8) + disp]) - } + (Size::S32, Location::Memory(value, disp)) => dynasm!(self ; neg [Rq(value as u8) + disp]), (Size::S64, Location::GPR(value)) => dynasm!(self ; neg Rq(value as u8)), - (Size::S64, Location::Memory(value, disp)) => { - dynasm!(self ; neg [Rq(value as u8) + disp]) - } + (Size::S64, Location::Memory(value, disp)) => dynasm!(self ; neg [Rq(value as u8) + disp]), _ => panic!("singlepass can't emit NEG {:?} {:?}", sz, value), } } @@ -1009,30 +997,18 @@ 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), }; } 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)) - } + (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), }; } @@ -1104,77 +1080,57 @@ 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)), } } 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)) - } + 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)), - XMMOrMemory::Memory(base, disp) => { - dynasm!(self ; ucomiss Rx(dst as u8), [Rq(base as u8) + disp]) - } + XMMOrMemory::Memory(base, disp) => dynasm!(self ; ucomiss Rx(dst as u8), [Rq(base as u8) + disp]), } } fn emit_ucomisd(&mut self, src: XMMOrMemory, dst: XMM) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; ucomisd Rx(dst as u8), Rx(x as u8)), - XMMOrMemory::Memory(base, disp) => { - dynasm!(self ; ucomisd Rx(dst as u8), [Rq(base as u8) + disp]) - } + XMMOrMemory::Memory(base, disp) => dynasm!(self ; ucomisd Rx(dst as u8), [Rq(base as u8) + disp]), } } fn emit_cvttss2si_32(&mut self, src: XMMOrMemory, dst: GPR) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; cvttss2si Rd(dst as u8), Rx(x as u8)), - XMMOrMemory::Memory(base, disp) => { - dynasm!(self ; cvttss2si Rd(dst as u8), [Rq(base as u8) + disp]) - } + XMMOrMemory::Memory(base, disp) => dynasm!(self ; cvttss2si Rd(dst as u8), [Rq(base as u8) + disp]), } } fn emit_cvttss2si_64(&mut self, src: XMMOrMemory, dst: GPR) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; cvttss2si Rq(dst as u8), Rx(x as u8)), - XMMOrMemory::Memory(base, disp) => { - dynasm!(self ; cvttss2si Rq(dst as u8), [Rq(base as u8) + disp]) - } + XMMOrMemory::Memory(base, disp) => dynasm!(self ; cvttss2si Rq(dst as u8), [Rq(base as u8) + disp]), } } fn emit_cvttsd2si_32(&mut self, src: XMMOrMemory, dst: GPR) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; cvttsd2si Rd(dst as u8), Rx(x as u8)), - XMMOrMemory::Memory(base, disp) => { - dynasm!(self ; cvttsd2si Rd(dst as u8), [Rq(base as u8) + disp]) - } + XMMOrMemory::Memory(base, disp) => dynasm!(self ; cvttsd2si Rd(dst as u8), [Rq(base as u8) + disp]), } } fn emit_cvttsd2si_64(&mut self, src: XMMOrMemory, dst: GPR) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; cvttsd2si Rq(dst as u8), Rx(x as u8)), - XMMOrMemory::Memory(base, disp) => { - dynasm!(self ; cvttsd2si Rq(dst as u8), [Rq(base as u8) + disp]) - } + XMMOrMemory::Memory(base, disp) => dynasm!(self ; cvttsd2si Rq(dst as u8), [Rq(base as u8) + disp]), } } From 06a7e5424b9dd464db241ccc6a72be622cfb4a37 Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 19 Nov 2019 02:39:51 +0800 Subject: [PATCH 168/342] Inline entry trampolines. --- lib/singlepass-backend/src/codegen_x64.rs | 142 ++++-------------- lib/singlepass-backend/src/emitter_x64.rs | 4 +- .../src/translator_aarch64.rs | 91 +++++++---- 3 files changed, 93 insertions(+), 144 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index cd2a729cb14..8bd2e330384 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -139,106 +139,6 @@ lazy_static! { }; } -#[cfg(target_arch = "aarch64")] -lazy_static! { - /// Performs a System V call to `target` with [stack_top..stack_base] as the argument list, from right to left. - static ref CONSTRUCT_STACK_AND_CALL_WASM: unsafe extern "C" fn (stack_top: *const u64, stack_base: *const u64, ctx: *mut vm::Ctx, target: *const vm::Func) -> u64 = { - let mut assembler = Assembler::new().unwrap(); - let offset = assembler.offset(); - dynasm!( - assembler - ; .arch aarch64 - ; sub sp, sp, 80 - ; str x19, [sp, 0] - ; str x20, [sp, 8] - ; str x21, [sp, 16] - ; str x22, [sp, 24] - ; str x23, [sp, 32] - ; str x24, [sp, 40] - ; str x25, [sp, 48] - ; str x26, [sp, 56] - ; str x27, [sp, 64] - ; str x28, [sp, 72] - ; mov x28, sp // WASM stack pointer - ; ldr x9, >v_65536 - ; sub sp, sp, x9 // Pre-allocate the WASM stack - - ; mov x19, x0 // stack_top - ; mov x20, x1 // stack_base - - // ctx - ; mov X(crate::translator_aarch64::map_gpr(GPR::RDI).x()), x2 - - // params - ; cmp x20, x19 - ; b.eq >end_copy_params - ; sub x20, x20, 8 - ; ldr X(crate::translator_aarch64::map_gpr(GPR::RSI).x()), [x20] - - ; cmp x20, x19 - ; b.eq >end_copy_params - ; sub x20, x20, 8 - ; ldr X(crate::translator_aarch64::map_gpr(GPR::RDX).x()), [x20] - - ; cmp x20, x19 - ; b.eq >end_copy_params - ; sub x20, x20, 8 - ; ldr X(crate::translator_aarch64::map_gpr(GPR::RCX).x()), [x20] - - ; cmp x20, x19 - ; b.eq >end_copy_params - ; sub x20, x20, 8 - ; ldr X(crate::translator_aarch64::map_gpr(GPR::R8).x()), [x20] - - ; cmp x20, x19 - ; b.eq >end_copy_params - ; sub x20, x20, 8 - ; ldr X(crate::translator_aarch64::map_gpr(GPR::R9).x()), [x20] - - ; copy_loop: - ; cmp x20, x19 - ; b.eq >end_copy_params - ; ldr x21, [x19] - ; add x19, x19, 8 - ; sub x28, x28, 8 - ; str x21, [x28] - ; b done - ; sub x28, x28, 8 - ; str x20, [x28] // Keep this consistent with RSP mapping in translator_aarch64 - - // Jump to target function! - ; br x3 - - ; done: - ; ldr x9, >v_65536 - ; add sp, sp, x9 // Resume stack pointer - ; ldr x19, [sp, 0] - ; ldr x20, [sp, 8] - ; ldr x21, [sp, 16] - ; ldr x22, [sp, 24] - ; ldr x23, [sp, 32] - ; ldr x24, [sp, 40] - ; ldr x25, [sp, 48] - ; ldr x26, [sp, 56] - ; ldr x27, [sp, 64] - ; ldr x28, [sp, 72] - ; add sp, sp, 80 - ; br x30 // LR - - ; v_65536: - ; .qword 1048576 - ); - let buf = assembler.finalize().unwrap(); - let ret = unsafe { ::std::mem::transmute(buf.ptr(offset)) }; - ::std::mem::forget(buf); - ret - }; -} - pub struct X64ModuleCodeGenerator { functions: Vec, signatures: Option>>, @@ -389,12 +289,32 @@ impl RunnableModule for X64ExecutionContext { let args_reverse: SmallVec<[u64; 8]> = args.iter().cloned().rev().collect(); let ret = match protect_unix::call_protected( || { - CONSTRUCT_STACK_AND_CALL_WASM( - args_reverse.as_ptr(), - args_reverse.as_ptr().offset(args_reverse.len() as isize), - ctx, - func.as_ptr(), - ) + #[cfg(target_arch = "x86_64")] + { + CONSTRUCT_STACK_AND_CALL_WASM( + args_reverse.as_ptr(), + args_reverse.as_ptr().offset(args_reverse.len() as isize), + ctx, + func.as_ptr(), + ) + } + #[cfg(target_arch = "aarch64")] + { + let callable: extern "C" fn(u64, u64, u64, u64, u64, u64) -> u64 = + std::mem::transmute(func); + if args.len() <= 5 { + callable( + ctx as u64, + args.get(0).cloned().unwrap_or(0), + args.get(1).cloned().unwrap_or(0), + args.get(2).cloned().unwrap_or(0), + args.get(3).cloned().unwrap_or(0), + args.get(4).cloned().unwrap_or(0), + ) + } else { + panic!("aarch64 backend currently supports at most 5 arguments"); + } + } }, Some(execution_context.breakpoints.clone()), ) { @@ -473,7 +393,6 @@ impl ModuleCodeGenerator { fn new() -> X64ModuleCodeGenerator { let mut a = Assembler::new().unwrap(); - a.notify_begin(); X64ModuleCodeGenerator { functions: vec![], @@ -521,15 +440,12 @@ impl ModuleCodeGenerator .or_insert_with(|| (assembler.new_dynamic_label(), None)); begin_label_info.1 = Some(begin_offset); + assembler.arch_emit_entry_trampoline(); let begin_label = begin_label_info.0; let mut machine = Machine::new(); machine.track_state = self.config.as_ref().unwrap().track_state; - dynasm!( - assembler - ; => begin_label - //; int 3 - ); + assembler.emit_label(begin_label); let code = X64FunctionCode { local_function_id: self.functions.len(), @@ -572,7 +488,6 @@ impl ModuleCodeGenerator ), }; - assembler.notify_end(); let total_size = assembler.get_offset().0; let _output = assembler.finalize().unwrap(); let mut output = CodeMemory::new(_output.len()); @@ -668,6 +583,7 @@ impl ModuleCodeGenerator let a = self.assembler.as_mut().unwrap(); let offset = a.offset(); + a.arch_emit_entry_trampoline(); let label = a.get_label(); a.emit_label(label); labels.insert(id, (label, Some(offset))); diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index 5a78554359d..dee97c85f83 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -280,8 +280,8 @@ pub trait Emitter { unimplemented!() } - fn notify_begin(&mut self) {} - fn notify_end(&mut self) {} + // Emits entry trampoline just before the real function. + fn arch_emit_entry_trampoline(&mut self) {} } fn _dummy(a: &mut Assembler) { diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index a26e2073b3e..f9d7076e9a4 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -1716,16 +1716,6 @@ impl Emitter for Assembler { ; adr x_tmp1, >done ; str x_tmp1, [x_rsp] ); - dynasm!(self - ; adr x_tmp1, >program_end - ; cmp X(map_gpr(x).x()), x_tmp1 - ; b.ge >external - ; adr x_tmp1, external - ; br X(map_gpr(x).x()) - ; external: - ); self.emit_homomorphic_host_redirection(x); dynasm!(self ; done: ); } @@ -1744,16 +1734,6 @@ impl Emitter for Assembler { // Read memory. ; ldr X(map_gpr(GPR::RAX).x()), [x_tmp3] ); - dynasm!(self - ; adr x_tmp1, >program_end - ; cmp X(map_gpr(GPR::RAX).x()), x_tmp1 - ; b.ge >external - ; adr x_tmp1, external - ; br X(map_gpr(GPR::RAX).x()) - ; external: - ); self.emit_homomorphic_host_redirection(GPR::RAX); dynasm!(self ; done: ); } @@ -1761,18 +1741,71 @@ impl Emitter for Assembler { } } - fn notify_begin(&mut self) { + fn arch_emit_entry_trampoline(&mut self) { dynasm!( self - ; program_begin: - ); - } + ; sub sp, sp, 96 + ; str x19, [sp, 0] + ; str x20, [sp, 8] + ; str x21, [sp, 16] + ; str x22, [sp, 24] + ; str x23, [sp, 32] + ; str x24, [sp, 40] + ; str x25, [sp, 48] + ; str x26, [sp, 56] + ; str x27, [sp, 64] + ; str x28, [sp, 72] + ; str x29, [sp, 80] + ; str x30, [sp, 88] + ; mov x28, sp // WASM stack pointer + ; ldr x9, >v_65536 + ; sub sp, sp, x9 // Pre-allocate the WASM stack + + // Fixup param locations. + ; str x0, [sp, 0] + ; str x1, [sp, 8] + ; str x2, [sp, 16] + ; str x3, [sp, 24] + ; str x4, [sp, 32] + ; str x5, [sp, 40] + ; ldr X(map_gpr(GPR::RDI).x()), [sp, 0] + ; ldr X(map_gpr(GPR::RSI).x()), [sp, 8] + ; ldr X(map_gpr(GPR::RDX).x()), [sp, 16] + ; ldr X(map_gpr(GPR::RCX).x()), [sp, 24] + ; ldr X(map_gpr(GPR::R8).x()), [sp, 32] + ; ldr X(map_gpr(GPR::R9).x()), [sp, 40] + + // return address + ; adr x20, >done + ; sub x28, x28, 8 + ; str x20, [x28] // Keep this consistent with RSP mapping in translator_aarch64 + + // Jump to target function! + ; b >real_entry - fn notify_end(&mut self) { - dynasm!( - self - ; program_end: - ); + ; done: + ; ldr x9, >v_65536 + ; add sp, sp, x9 // Resume stack pointer + ; ldr x19, [sp, 0] + ; ldr x20, [sp, 8] + ; ldr x21, [sp, 16] + ; ldr x22, [sp, 24] + ; ldr x23, [sp, 32] + ; ldr x24, [sp, 40] + ; ldr x25, [sp, 48] + ; ldr x26, [sp, 56] + ; ldr x27, [sp, 64] + ; ldr x28, [sp, 72] + ; ldr x29, [sp, 80] + ; ldr x30, [sp, 88] + ; add sp, sp, 96 + ; br x30 // LR + + ; v_65536: + ; .qword 1048576 + + ; real_entry: + ) } } From ddbdb3e585023e7a25f8fc35cdc84725b6e76d89 Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 19 Nov 2019 02:46:31 +0800 Subject: [PATCH 169/342] Ignore extra arguments. --- lib/singlepass-backend/src/codegen_x64.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 8bd2e330384..a4bf224ff17 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -302,18 +302,14 @@ impl RunnableModule for X64ExecutionContext { { let callable: extern "C" fn(u64, u64, u64, u64, u64, u64) -> u64 = std::mem::transmute(func); - if args.len() <= 5 { - callable( - ctx as u64, - args.get(0).cloned().unwrap_or(0), - args.get(1).cloned().unwrap_or(0), - args.get(2).cloned().unwrap_or(0), - args.get(3).cloned().unwrap_or(0), - args.get(4).cloned().unwrap_or(0), - ) - } else { - panic!("aarch64 backend currently supports at most 5 arguments"); - } + callable( + ctx as u64, + args.get(0).cloned().unwrap_or(0), + args.get(1).cloned().unwrap_or(0), + args.get(2).cloned().unwrap_or(0), + args.get(3).cloned().unwrap_or(0), + args.get(4).cloned().unwrap_or(0), + ); } }, Some(execution_context.breakpoints.clone()), From 2776daedfab7cba5f19611e4e6741bc62995ac72 Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 19 Nov 2019 03:04:07 +0800 Subject: [PATCH 170/342] Fix entry with more than 5/6 arguments. --- lib/singlepass-backend/src/codegen_x64.rs | 78 +++++++++++++++++-- .../src/translator_aarch64.rs | 35 +++++---- 2 files changed, 89 insertions(+), 24 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index a4bf224ff17..980400e56d6 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -300,16 +300,78 @@ impl RunnableModule for X64ExecutionContext { } #[cfg(target_arch = "aarch64")] { - let callable: extern "C" fn(u64, u64, u64, u64, u64, u64) -> u64 = - std::mem::transmute(func); + // Fix this + let callable: extern "C" fn( + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + ) -> u64 = std::mem::transmute(func); + let mut args = args.iter(); callable( ctx as u64, - args.get(0).cloned().unwrap_or(0), - args.get(1).cloned().unwrap_or(0), - args.get(2).cloned().unwrap_or(0), - args.get(3).cloned().unwrap_or(0), - args.get(4).cloned().unwrap_or(0), - ); + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + ) } }, Some(execution_context.breakpoints.clone()), diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index f9d7076e9a4..c3ad766906a 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -1744,22 +1744,11 @@ impl Emitter for Assembler { fn arch_emit_entry_trampoline(&mut self) { dynasm!( self - ; sub sp, sp, 96 - ; str x19, [sp, 0] - ; str x20, [sp, 8] - ; str x21, [sp, 16] - ; str x22, [sp, 24] - ; str x23, [sp, 32] - ; str x24, [sp, 40] - ; str x25, [sp, 48] - ; str x26, [sp, 56] - ; str x27, [sp, 64] - ; str x28, [sp, 72] - ; str x29, [sp, 80] - ; str x30, [sp, 88] + ; mov x18, x28 ; mov x28, sp // WASM stack pointer ; ldr x9, >v_65536 ; sub sp, sp, x9 // Pre-allocate the WASM stack + ; sub x28, x28, 16 // for the last two arguments // Fixup param locations. ; str x0, [sp, 0] @@ -1768,6 +1757,8 @@ impl Emitter for Assembler { ; str x3, [sp, 24] ; str x4, [sp, 32] ; str x5, [sp, 40] + ; str x6, [x28, 0] + ; str x7, [x28, 8] ; ldr X(map_gpr(GPR::RDI).x()), [sp, 0] ; ldr X(map_gpr(GPR::RSI).x()), [sp, 8] ; ldr X(map_gpr(GPR::RDX).x()), [sp, 16] @@ -1775,6 +1766,19 @@ impl Emitter for Assembler { ; ldr X(map_gpr(GPR::R8).x()), [sp, 32] ; ldr X(map_gpr(GPR::R9).x()), [sp, 40] + ; str x19, [sp, 0] + ; str x20, [sp, 8] + ; str x21, [sp, 16] + ; str x22, [sp, 24] + ; str x23, [sp, 32] + ; str x24, [sp, 40] + ; str x25, [sp, 48] + ; str x26, [sp, 56] + ; str x27, [sp, 64] + ; str x18, [sp, 72] // previously x28 + ; str x29, [sp, 80] + ; str x30, [sp, 88] + // return address ; adr x20, >done ; sub x28, x28, 8 @@ -1784,8 +1788,6 @@ impl Emitter for Assembler { ; b >real_entry ; done: - ; ldr x9, >v_65536 - ; add sp, sp, x9 // Resume stack pointer ; ldr x19, [sp, 0] ; ldr x20, [sp, 8] ; ldr x21, [sp, 16] @@ -1798,7 +1800,8 @@ impl Emitter for Assembler { ; ldr x28, [sp, 72] ; ldr x29, [sp, 80] ; ldr x30, [sp, 88] - ; add sp, sp, 96 + ; ldr x9, >v_65536 + ; add sp, sp, x9 // Resume stack pointer ; br x30 // LR ; v_65536: From 8ebf8986f0dec8523bbc5268e2dc9c0e5795daf8 Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 19 Nov 2019 03:15:12 +0800 Subject: [PATCH 171/342] Reduce stack size. --- lib/singlepass-backend/src/translator_aarch64.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index c3ad766906a..a8150092eac 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -1805,7 +1805,7 @@ impl Emitter for Assembler { ; br x30 // LR ; v_65536: - ; .qword 1048576 + ; .qword 262144 ; real_entry: ) From 8b6a7b77fc32034205a041cc8062141ca87fbac7 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Sat, 16 Nov 2019 11:25:33 -0800 Subject: [PATCH 172/342] Clean up from feedback --- lib/singlepass-backend/src/codegen_x64.rs | 41 ++++++++---------- src/bin/wasmer.rs | 52 ++++++++++++----------- 2 files changed, 46 insertions(+), 47 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 1b9e5e7dd04..13333df90fe 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -658,36 +658,34 @@ impl X64FunctionCode { sz_dst: Size, dst: Location, ) { - let tmp_src = m.acquire_temp_gpr().unwrap(); - let tmp_dst = m.acquire_temp_gpr().unwrap(); - - match src { - Location::Imm32(_) | Location::Imm64(_) => { - a.emit_mov(Size::S64, src, Location::GPR(tmp_src)); - src = Location::GPR(tmp_src); - } - Location::GPR(_) => { - a.emit_mov(Size::S64, src, Location::GPR(tmp_src)); - src = Location::GPR(tmp_src); - } - Location::Memory(_, _) => {} - _ => unreachable!(), - } - - match dst { + let inner = |m: &mut Machine, a: &mut Assembler, src: Location| match dst { Location::Imm32(_) | Location::Imm64(_) => unreachable!(), Location::Memory(_, _) => { + let tmp_dst = m.acquire_temp_gpr().unwrap(); op(a, sz_src, src, sz_dst, Location::GPR(tmp_dst)); a.emit_mov(Size::S64, Location::GPR(tmp_dst), dst); + + m.release_temp_gpr(tmp_dst); } Location::GPR(_) => { op(a, sz_src, src, sz_dst, dst); } _ => unreachable!(), - } + }; - m.release_temp_gpr(tmp_dst); - m.release_temp_gpr(tmp_src); + match src { + Location::Imm32(_) | Location::Imm64(_) => { + let tmp_src = m.acquire_temp_gpr().unwrap(); + a.emit_mov(Size::S64, src, Location::GPR(tmp_src)); + src = Location::GPR(tmp_src); + + inner(m, a, src); + + m.release_temp_gpr(tmp_src); + } + Location::GPR(_) | Location::Memory(_, _) => inner(m, a, src), + _ => unreachable!(), + } } /// Moves `src` and `dst` to valid locations for generic instructions. @@ -2964,7 +2962,6 @@ impl FunctionCodeGenerator for X64FunctionCode { let tmpg1 = self.machine.acquire_temp_gpr().unwrap(); a.emit_mov(Size::S32, loc, Location::GPR(tmpg1)); - a.emit_and(Size::S32, Location::Imm32(0xFF), Location::GPR(tmpg1)); Self::emit_relaxed_zx_sx( a, &mut self.machine, @@ -2988,7 +2985,6 @@ impl FunctionCodeGenerator for X64FunctionCode { let tmpg1 = self.machine.acquire_temp_gpr().unwrap(); a.emit_mov(Size::S32, loc, Location::GPR(tmpg1)); - a.emit_and(Size::S32, Location::Imm32(0xFFFF), Location::GPR(tmpg1)); Self::emit_relaxed_zx_sx( a, &mut self.machine, @@ -3036,7 +3032,6 @@ impl FunctionCodeGenerator for X64FunctionCode { let tmpg1 = self.machine.acquire_temp_gpr().unwrap(); a.emit_mov(Size::S32, loc, Location::GPR(tmpg1)); - a.emit_and(Size::S32, Location::Imm32(0xFFFF), Location::GPR(tmpg1)); Self::emit_relaxed_zx_sx( a, &mut self.machine, diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 74f3ef4700f..0caaefe22a1 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -96,6 +96,29 @@ struct PrestandardFeatures { all: bool, } +impl PrestandardFeatures { + /// Generate [`wabt::Features`] struct from CLI options + pub fn into_wabt_features(&self) -> wabt::Features { + let mut features = wabt::Features::new(); + if self.simd || self.all { + features.enable_simd(); + } + if self.threads || self.all { + features.enable_threads(); + } + features.enable_sign_extension(); + features + } + + /// Generate [`Features`] struct from CLI options + pub fn into_backend_features(&self) -> Features { + Features { + simd: self.simd || self.all, + threads: self.threads || self.all, + } + } +} + #[cfg(feature = "backend-llvm")] #[derive(Debug, StructOpt, Clone)] /// LLVM backend flags. @@ -393,14 +416,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { } if !utils::is_wasm_binary(&wasm_binary) { - let mut features = wabt::Features::new(); - features.enable_sign_extension(); - if options.features.simd || options.features.all { - features.enable_simd(); - } - if options.features.threads || options.features.all { - features.enable_threads(); - } + let features = options.features.into_wabt_features(); wasm_binary = wabt::wat2wasm_with_features(wasm_binary, features) .map_err(|e| format!("Can't convert from wast to wasm: {:?}", e))?; } @@ -444,10 +460,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { memory_bound_check_mode: MemoryBoundCheckMode::Disable, enforce_stack_check: true, track_state, - features: Features { - simd: options.features.simd || options.features.all, - threads: options.features.threads || options.features.all, - }, + features: options.features.into_backend_features(), }, &*compiler, ) @@ -458,10 +471,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { CompilerConfig { symbol_map: em_symbol_map.clone(), track_state, - features: Features { - simd: options.features.simd || options.features.all, - threads: options.features.threads || options.features.all, - }, + features: options.features.into_backend_features(), ..Default::default() }, &*compiler, @@ -506,10 +516,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { CompilerConfig { symbol_map: em_symbol_map.clone(), track_state, - features: Features { - simd: options.features.simd || options.features.all, - threads: options.features.threads || options.features.all, - }, + features: options.features.into_backend_features(), ..Default::default() }, &*compiler, @@ -807,10 +814,7 @@ fn validate_wasm(validate: Validate) -> Result<(), String> { wasmer_runtime_core::validate_and_report_errors_with_features( &wasm_binary, - Features { - simd: validate.features.simd || validate.features.all, - threads: validate.features.threads || validate.features.all, - }, + validate.features.into_backend_features(), ) .map_err(|err| format!("Validation failed: {}", err))?; From 8a096a09e4ea9724379de86319f66f35d9084bfb Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 18 Nov 2019 11:47:58 -0800 Subject: [PATCH 173/342] Remove extra register use in sign extension instructions --- lib/singlepass-backend/src/codegen_x64.rs | 26 +++++------------------ 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index c7154d21519..e825c32e3b8 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -2964,18 +2964,15 @@ impl FunctionCodeGenerator for X64FunctionCode { )[0]; self.value_stack.push(ret); - let tmpg1 = self.machine.acquire_temp_gpr().unwrap(); - a.emit_mov(Size::S32, loc, Location::GPR(tmpg1)); Self::emit_relaxed_zx_sx( a, &mut self.machine, Assembler::emit_movsx, Size::S8, - Location::GPR(tmpg1), + loc, Size::S32, ret, ); - self.machine.release_temp_gpr(tmpg1); } Operator::I32Extend16S => { let loc = @@ -2987,18 +2984,15 @@ impl FunctionCodeGenerator for X64FunctionCode { )[0]; self.value_stack.push(ret); - let tmpg1 = self.machine.acquire_temp_gpr().unwrap(); - a.emit_mov(Size::S32, loc, Location::GPR(tmpg1)); Self::emit_relaxed_zx_sx( a, &mut self.machine, Assembler::emit_movsx, Size::S16, - Location::GPR(tmpg1), + loc, Size::S32, ret, ); - self.machine.release_temp_gpr(tmpg1); } Operator::I64Extend8S => { let loc = @@ -3010,19 +3004,15 @@ impl FunctionCodeGenerator for X64FunctionCode { )[0]; self.value_stack.push(ret); - let tmpg1 = self.machine.acquire_temp_gpr().unwrap(); - a.emit_mov(Size::S32, loc, Location::GPR(tmpg1)); - a.emit_and(Size::S32, Location::Imm32(0xFF), Location::GPR(tmpg1)); Self::emit_relaxed_zx_sx( a, &mut self.machine, Assembler::emit_movsx, Size::S8, - Location::GPR(tmpg1), + loc, Size::S64, ret, ); - self.machine.release_temp_gpr(tmpg1); } Operator::I64Extend16S => { let loc = @@ -3034,18 +3024,15 @@ impl FunctionCodeGenerator for X64FunctionCode { )[0]; self.value_stack.push(ret); - let tmpg1 = self.machine.acquire_temp_gpr().unwrap(); - a.emit_mov(Size::S32, loc, Location::GPR(tmpg1)); Self::emit_relaxed_zx_sx( a, &mut self.machine, Assembler::emit_movsx, Size::S16, - Location::GPR(tmpg1), + loc, Size::S64, ret, ); - self.machine.release_temp_gpr(tmpg1); } Operator::I64Extend32S => { let loc = @@ -3057,18 +3044,15 @@ impl FunctionCodeGenerator for X64FunctionCode { )[0]; self.value_stack.push(ret); - let tmpg1 = self.machine.acquire_temp_gpr().unwrap(); - a.emit_mov(Size::S32, loc, Location::GPR(tmpg1)); Self::emit_relaxed_zx_sx( a, &mut self.machine, Assembler::emit_movsx, Size::S32, - Location::GPR(tmpg1), + loc, Size::S64, ret, ); - self.machine.release_temp_gpr(tmpg1); } Operator::I32WrapI64 => { let loc = From 95368aa5dc2c6ea78e1bf2958a15b66250393a8a Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Mon, 18 Nov 2019 13:19:05 -0800 Subject: [PATCH 174/342] Trigger azure pipeline job on new tag --- azure-pipelines.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a8b571e28a0..23f806dca1e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -205,7 +205,7 @@ jobs: dependsOn: - Build_CLI - Build_Library - condition: eq(variables['Build.SourceBranch'], 'refs/heads/master') + condition: or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), startsWith(variables['Build.SourceBranch'], 'refs/tags')) steps: # - download: current - task: DownloadPipelineArtifact@1 @@ -259,3 +259,4 @@ trigger: - master - staging - trying + - refs/tags/* From 41c1e071c801e57269ea62fb5290fb316fd8f2a6 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Mon, 18 Nov 2019 15:42:08 -0800 Subject: [PATCH 175/342] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c55256d897..5ed6bfc742f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,10 @@ ## **[Unreleased]** -## 0.10.2 - 2019-11-15 +## 0.10.2 - 2019-11-18 - [#968](https://github.com/wasmerio/wasmer/pull/968) Added `--invoke` option to the command +- [#964](https://github.com/wasmerio/wasmer/pull/964) Enable cross-compilation for specific target - [#971](https://github.com/wasmerio/wasmer/pull/971) In LLVM backend, use unaligned loads and stores for non-atomic accesses to wasmer memory. - [#960](https://github.com/wasmerio/wasmer/pull/960) Fix `runtime-c-api` header files when compiled by clang. - [#925](https://github.com/wasmerio/wasmer/pull/925) Host functions can be closures with a captured environment. From a7577dfcefe300c6ac13faa3015ca9b0d46c9da1 Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 20 Nov 2019 00:37:38 +0800 Subject: [PATCH 176/342] Try further reducing preallocated stack size. --- lib/singlepass-backend/src/translator_aarch64.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index a8150092eac..0bd5430ef02 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -1805,7 +1805,7 @@ impl Emitter for Assembler { ; br x30 // LR ; v_65536: - ; .qword 262144 + ; .qword 131072 ; real_entry: ) From 3d4811558605eb6e28d5d9e2e255131381b0ff8a Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 20 Nov 2019 01:07:02 +0800 Subject: [PATCH 177/342] Allocate a big enough stack for invoke(). --- lib/singlepass-backend/src/codegen_x64.rs | 219 ++++++++++++------ .../src/translator_aarch64.rs | 2 +- 2 files changed, 149 insertions(+), 72 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 980400e56d6..f0e4833357f 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -139,6 +139,44 @@ lazy_static! { }; } +#[cfg(target_arch = "aarch64")] +#[repr(C)] +struct CallCtx { + ctx: *mut vm::Ctx, + stack: *mut u64, + target: *mut u8, +} + +#[cfg(target_arch = "aarch64")] +lazy_static! { + /// Switches stack and executes the provided callback. + static ref SWITCH_STACK: unsafe extern "C" fn (stack: *mut u64, cb: extern "C" fn (*mut u8) -> u64, userdata: *mut u8) -> u64 = { + let mut assembler = Assembler::new().unwrap(); + let offset = assembler.offset(); + dynasm!( + assembler + ; .arch aarch64 + ; sub x0, x0, 16 + ; mov x8, sp + ; str x8, [x0, 0] + ; str x30, [x0, 8] + ; adr x30, >done + ; mov sp, x0 + ; mov x0, x2 + ; br x1 + ; done: + ; ldr x30, [sp, 8] + ; ldr x8, [sp, 0] + ; mov sp, x8 + ; br x30 + ); + let buf = assembler.finalize().unwrap(); + let ret = unsafe { mem::transmute(buf.ptr(offset)) }; + mem::forget(buf); + ret + }; +} + pub struct X64ModuleCodeGenerator { functions: Vec, signatures: Option>>, @@ -300,77 +338,116 @@ impl RunnableModule for X64ExecutionContext { } #[cfg(target_arch = "aarch64")] { - // Fix this - let callable: extern "C" fn( - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - u64, - ) -> u64 = std::mem::transmute(func); - let mut args = args.iter(); - callable( - ctx as u64, - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), - args.next().cloned().unwrap_or(0), + struct CallCtx<'a> { + args: &'a [u64], + ctx: *mut vm::Ctx, + callable: NonNull, + } + extern "C" fn call_fn(f: *mut u8) -> u64 { + unsafe { + let f = &*(f as *const CallCtx); + let callable: extern "C" fn( + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64, + ) + -> u64 = std::mem::transmute(f.callable); + let mut args = f.args.iter(); + callable( + f.ctx as u64, + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + args.next().cloned().unwrap_or(0), + ) + } + } + let mut cctx = CallCtx { + args: &args, + ctx: ctx, + callable: func, + }; + use libc::{ + mmap, mprotect, MAP_ANON, MAP_NORESERVE, MAP_PRIVATE, PROT_READ, + PROT_WRITE, + }; + const STACK_SIZE: usize = 1048576 * 1024; // 1GB of virtual addrss space for stack. + let stack_ptr = unsafe { + mmap( + ::std::ptr::null_mut(), + STACK_SIZE, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, + -1, + 0, + ) + }; + if stack_ptr as isize == -1 { + panic!("unable to allocate stack"); + } + // TODO: Mark specific regions in the stack as PROT_NONE. + SWITCH_STACK( + (stack_ptr as *mut u8).offset(STACK_SIZE as isize) as *mut u64, + call_fn, + &mut cctx as *mut CallCtx as *mut u8, ) } }, diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 0bd5430ef02..c0e62d4b483 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -1805,7 +1805,7 @@ impl Emitter for Assembler { ; br x30 // LR ; v_65536: - ; .qword 131072 + ; .qword 524288 ; real_entry: ) From 85b1935366bdaa39e545608090fc5c5688786cb4 Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 20 Nov 2019 01:22:56 +0800 Subject: [PATCH 178/342] Uncomment previously disabled test. --- lib/spectests/spectests/start.wast | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/spectests/spectests/start.wast b/lib/spectests/spectests/start.wast index 38c4f668783..6719edba871 100644 --- a/lib/spectests/spectests/start.wast +++ b/lib/spectests/spectests/start.wast @@ -89,10 +89,10 @@ (start $main) ) -;; (module -;; (func $print (import "spectest" "print")) -;; (start $print) -;; ) +(module + (func $print (import "spectest" "print")) + (start $print) +) (assert_trap (module (func $main (unreachable)) (start $main)) From 98052f82b992f515159c65dbadfe83cc0b1f86b8 Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 20 Nov 2019 01:27:48 +0800 Subject: [PATCH 179/342] Unmap stack after call. --- lib/singlepass-backend/src/codegen_x64.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index f0e4833357f..f8fb82d264f 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -426,10 +426,10 @@ impl RunnableModule for X64ExecutionContext { callable: func, }; use libc::{ - mmap, mprotect, MAP_ANON, MAP_NORESERVE, MAP_PRIVATE, PROT_READ, + mmap, munmap, MAP_ANON, MAP_NORESERVE, MAP_PRIVATE, PROT_READ, PROT_WRITE, }; - const STACK_SIZE: usize = 1048576 * 1024; // 1GB of virtual addrss space for stack. + const STACK_SIZE: usize = 1048576 * 1024; // 1GB of virtual address space for stack. let stack_ptr = unsafe { mmap( ::std::ptr::null_mut(), @@ -444,11 +444,13 @@ impl RunnableModule for X64ExecutionContext { panic!("unable to allocate stack"); } // TODO: Mark specific regions in the stack as PROT_NONE. - SWITCH_STACK( + let ret = SWITCH_STACK( (stack_ptr as *mut u8).offset(STACK_SIZE as isize) as *mut u64, call_fn, &mut cctx as *mut CallCtx as *mut u8, - ) + ); + munmap(stack_ptr, STACK_SIZE); + ret } }, Some(execution_context.breakpoints.clone()), From 34bb321e66c9950e6889a289953b94b96397807d Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 20 Nov 2019 01:34:45 +0800 Subject: [PATCH 180/342] Rename `emit_host_redirection`. --- lib/singlepass-backend/src/codegen_x64.rs | 6 +++--- lib/singlepass-backend/src/emitter_x64.rs | 4 ++-- lib/singlepass-backend/src/translator_aarch64.rs | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index f8fb82d264f..f2af8d9c97f 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -754,7 +754,7 @@ impl ModuleCodeGenerator Location::Memory(GPR::RAX, imported_func_addr as i32), Location::GPR(GPR::RAX), ); - a.emit_homomorphic_host_redirection(GPR::RAX); + a.emit_host_redirection(GPR::RAX); self.func_import_count += 1; @@ -5444,7 +5444,7 @@ impl FunctionCodeGenerator for X64FunctionCode { let after = a.get_label(); a.emit_jmp(Condition::None, after); a.emit_label(label); - a.emit_homomorphic_host_redirection(GPR::RAX); + a.emit_host_redirection(GPR::RAX); a.emit_label(after); a.emit_call_label(label); }, @@ -5489,7 +5489,7 @@ impl FunctionCodeGenerator for X64FunctionCode { let after = a.get_label(); a.emit_jmp(Condition::None, after); a.emit_label(label); - a.emit_homomorphic_host_redirection(GPR::RAX); + a.emit_host_redirection(GPR::RAX); a.emit_label(after); a.emit_call_label(label); }, diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index dee97c85f83..e929f0f5c99 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -189,7 +189,7 @@ pub trait Emitter { fn emit_bkpt(&mut self); - fn emit_homomorphic_host_redirection(&mut self, target: GPR); + fn emit_host_redirection(&mut self, target: GPR); fn emit_inline_breakpoint(&mut self, ty: InlineBreakpointType); fn arch_has_itruncf(&self) -> bool { @@ -1311,7 +1311,7 @@ impl Emitter for Assembler { dynasm!(self ; int 0x3); } - fn emit_homomorphic_host_redirection(&mut self, target: GPR) { + fn emit_host_redirection(&mut self, target: GPR) { self.emit_jmp_location(Location::GPR(target)); } diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index c0e62d4b483..971bbfdea91 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -1637,7 +1637,7 @@ impl Emitter for Assembler { dynasm!(self ; .dword 0 ; .dword 1) } - fn emit_homomorphic_host_redirection(&mut self, target: GPR) { + fn emit_host_redirection(&mut self, target: GPR) { let target = map_gpr(target); dynasm!( self @@ -1716,7 +1716,7 @@ impl Emitter for Assembler { ; adr x_tmp1, >done ; str x_tmp1, [x_rsp] ); - self.emit_homomorphic_host_redirection(x); + self.emit_host_redirection(x); dynasm!(self ; done: ); } Location::Memory(base, disp) => { @@ -1734,7 +1734,7 @@ impl Emitter for Assembler { // Read memory. ; ldr X(map_gpr(GPR::RAX).x()), [x_tmp3] ); - self.emit_homomorphic_host_redirection(GPR::RAX); + self.emit_host_redirection(GPR::RAX); dynasm!(self ; done: ); } _ => unreachable!(), From c9aa37fc99b795e8fb50e2e35860710eebb955eb Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 20 Nov 2019 01:48:20 +0800 Subject: [PATCH 181/342] Cleanup. --- lib/singlepass-backend/src/codegen_x64.rs | 29 ++++--- lib/singlepass-backend/src/emitter_x64.rs | 7 -- lib/singlepass-backend/src/lib.rs | 5 +- .../src/translator_aarch64.rs | 84 +++++++------------ 4 files changed, 51 insertions(+), 74 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index f2af8d9c97f..bcdde8c3382 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -46,8 +46,10 @@ use wasmer_runtime_core::{ }; #[cfg(target_arch = "aarch64")] +#[allow(dead_code)] static ARCH: Architecture = Architecture::Aarch64; #[cfg(target_arch = "x86_64")] +#[allow(dead_code)] static ARCH: Architecture = Architecture::X64; #[cfg(target_arch = "x86_64")] @@ -141,6 +143,7 @@ lazy_static! { #[cfg(target_arch = "aarch64")] #[repr(C)] +#[allow(dead_code)] struct CallCtx { ctx: *mut vm::Ctx, stack: *mut u64, @@ -324,11 +327,12 @@ impl RunnableModule for X64ExecutionContext { 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( || { #[cfg(target_arch = "x86_64")] { + let args_reverse: SmallVec<[u64; 8]> = args.iter().cloned().rev().collect(); CONSTRUCT_STACK_AND_CALL_WASM( args_reverse.as_ptr(), args_reverse.as_ptr().offset(args_reverse.len() as isize), @@ -430,16 +434,14 @@ impl RunnableModule for X64ExecutionContext { PROT_WRITE, }; const STACK_SIZE: usize = 1048576 * 1024; // 1GB of virtual address space for stack. - let stack_ptr = unsafe { - mmap( - ::std::ptr::null_mut(), - STACK_SIZE, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, - -1, - 0, - ) - }; + let stack_ptr = mmap( + ::std::ptr::null_mut(), + STACK_SIZE, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, + -1, + 0, + ); if stack_ptr as isize == -1 { panic!("unable to allocate stack"); } @@ -529,7 +531,7 @@ impl ModuleCodeGenerator for X64ModuleCodeGenerator { fn new() -> X64ModuleCodeGenerator { - let mut a = Assembler::new().unwrap(); + let a = Assembler::new().unwrap(); X64ModuleCodeGenerator { functions: vec![], @@ -612,7 +614,7 @@ impl ModuleCodeGenerator mut self, _: &ModuleInfo, ) -> Result<(X64ExecutionContext, Box), CodegenError> { - let (mut assembler, function_labels, breakpoints) = match self.functions.last_mut() { + let (assembler, function_labels, breakpoints) = match self.functions.last_mut() { Some(x) => ( x.assembler.take().unwrap(), x.function_labels.take().unwrap(), @@ -797,6 +799,7 @@ impl X64FunctionCode { .insert(m.state.wasm_inst_offset, SuspendOffset::Trappable(offset)); } + #[allow(dead_code)] fn mark_inline_breakpoint( a: &mut Assembler, m: &Machine, diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index e929f0f5c99..acb711a96c3 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -284,13 +284,6 @@ pub trait Emitter { fn arch_emit_entry_trampoline(&mut self) {} } -fn _dummy(a: &mut Assembler) { - dynasm!( - self - ; .arch x64 - ); -} - macro_rules! unop_gpr { ($ins:ident, $assembler:tt, $sz:expr, $loc:expr, $otherwise:block) => { match ($sz, $loc) { diff --git a/lib/singlepass-backend/src/lib.rs b/lib/singlepass-backend/src/lib.rs index f88f1e8fa4d..b920b56cdf3 100644 --- a/lib/singlepass-backend/src/lib.rs +++ b/lib/singlepass-backend/src/lib.rs @@ -1,4 +1,4 @@ -/*#![deny( +#![deny( dead_code, nonstandard_style, unused_imports, @@ -6,7 +6,7 @@ unused_variables, unused_unsafe, unreachable_patterns -)]*/ +)] #![feature(proc_macro_hygiene)] #![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")] #![doc(html_logo_url = "https://avatars3.githubusercontent.com/u/44205449?s=200&v=4")] @@ -34,6 +34,7 @@ mod codegen_x64; mod emitter_x64; mod machine; pub mod protect_unix; +#[cfg(target_arch = "aarch64")] mod translator_aarch64; pub use codegen_x64::X64FunctionCode as FunctionCodeGenerator; diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 971bbfdea91..0c2b7a6ecbf 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -1,6 +1,5 @@ #![allow(dead_code)] -use crate::codegen_x64::*; use crate::emitter_x64::*; use dynasmrt::{aarch64::Assembler, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi}; use wasmer_runtime_core::backend::InlineBreakpointType; @@ -106,7 +105,7 @@ pub fn map_xmm(xmm: XMM) -> AV { } pub fn get_aarch64_assembler() -> Assembler { - let mut a = Assembler::new().unwrap(); + let a = Assembler::new().unwrap(); dynasm!( a ; .arch aarch64 @@ -201,24 +200,6 @@ macro_rules! binop_imm32_mem { }; } -macro_rules! binop_imm64_gpr { - ($ins:ident, $assembler:tt, $sz:expr, $src:expr, $dst:expr, $otherwise:block) => { - match ($sz, $src, $dst) { - (Size::S64, Location::Imm64(src), Location::GPR(dst)) => { - dynasm!($assembler - ; b >after - ; data: - ; .qword src as i64 - ; after: - ; ldr x_tmp1, $otherwise - } - }; -} - macro_rules! binop_gpr_gpr { ($ins:ident, $assembler:tt, $sz:expr, $src:expr, $dst:expr, $otherwise:block) => { match ($sz, $src, $dst) { @@ -1185,10 +1166,10 @@ impl Emitter for Assembler { fn emit_or(&mut self, sz: Size, src: Location, dst: Location) { binop_all_nofp!(orr, self, sz, src, dst, { unreachable!("or") }); } - fn emit_bsr(&mut self, sz: Size, src: Location, dst: Location) { + fn emit_bsr(&mut self, _sz: Size, _src: Location, _dst: Location) { unimplemented!("aarch64: bsr"); } - fn emit_bsf(&mut self, sz: Size, src: Location, dst: Location) { + fn emit_bsf(&mut self, _sz: Size, _src: Location, _dst: Location) { unimplemented!("aarch64: bsf"); } fn arch_has_xzcnt(&self) -> bool { @@ -1200,7 +1181,7 @@ impl Emitter for Assembler { fn arch_emit_tzcnt(&mut self, sz: Size, src: Location, dst: Location) { emit_clz_variant(self, sz, &src, &dst, true); } - fn emit_neg(&mut self, sz: Size, value: Location) { + fn emit_neg(&mut self, _sz: Size, _value: Location) { unimplemented!("aarch64: neg"); } fn emit_popcnt(&mut self, sz: Size, src: Location, dst: Location) { @@ -1372,45 +1353,45 @@ impl Emitter for Assembler { } } - fn emit_xchg(&mut self, sz: Size, src: Location, dst: Location) { + fn emit_xchg(&mut self, _sz: Size, _src: Location, _dst: Location) { unimplemented!("aarch64: xchg") } - fn emit_lock_xadd(&mut self, sz: Size, src: Location, dst: Location) { + fn emit_lock_xadd(&mut self, _sz: Size, _src: Location, _dst: Location) { unimplemented!("aarch64: xadd") } - fn emit_lock_cmpxchg(&mut self, sz: Size, src: Location, dst: Location) { + fn emit_lock_cmpxchg(&mut self, _sz: Size, _src: Location, _dst: Location) { unimplemented!("aarch64: cmpxchg") } - fn emit_vmovaps(&mut self, src: XMMOrMemory, dst: XMMOrMemory) { + fn emit_vmovaps(&mut self, _src: XMMOrMemory, _dst: XMMOrMemory) { unimplemented!("aarch64: vmovaps") } - fn emit_vmovapd(&mut self, src: XMMOrMemory, dst: XMMOrMemory) { + fn emit_vmovapd(&mut self, _src: XMMOrMemory, _dst: XMMOrMemory) { unimplemented!("aarch64: vmovapd") } - fn emit_vxorps(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + fn emit_vxorps(&mut self, _src1: XMM, _src2: XMMOrMemory, _dst: XMM) { unimplemented!("aarch64: vxorps") } - fn emit_vxorpd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + fn emit_vxorpd(&mut self, _src1: XMM, _src2: XMMOrMemory, _dst: XMM) { unimplemented!("aarch64: vxorpd") } - fn emit_vcmpunordss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + fn emit_vcmpunordss(&mut self, _src1: XMM, _src2: XMMOrMemory, _dst: XMM) { unimplemented!("aarch64: vcmpunordss") } - fn emit_vcmpunordsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + fn emit_vcmpunordsd(&mut self, _src1: XMM, _src2: XMMOrMemory, _dst: XMM) { unimplemented!("aarch64: vcmpunordsd") } - fn emit_vcmpordss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + fn emit_vcmpordss(&mut self, _src1: XMM, _src2: XMMOrMemory, _dst: XMM) { unimplemented!("aarch64: vcmpordss") } - fn emit_vcmpordsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + fn emit_vcmpordsd(&mut self, _src1: XMM, _src2: XMMOrMemory, _dst: XMM) { unimplemented!("aarch64: vcmpordsd") } - fn emit_vblendvps(&mut self, src1: XMM, src2: XMMOrMemory, mask: XMM, dst: XMM) { + fn emit_vblendvps(&mut self, _src1: XMM, _src2: XMMOrMemory, _mask: XMM, _dst: XMM) { unimplemented!("aarch64: vblendvps") } - fn emit_vblendvpd(&mut self, src1: XMM, src2: XMMOrMemory, mask: XMM, dst: XMM) { + fn emit_vblendvpd(&mut self, _src1: XMM, _src2: XMMOrMemory, _mask: XMM, _dst: XMM) { unimplemented!("aarch64: vblendvpd") } @@ -1518,50 +1499,49 @@ impl Emitter for Assembler { dynasm!(self ; fneg D(map_xmm(dst).v()), D(map_xmm(src).v())); } - // These instructions are only used in itruncf-type/fconverti-type opcodes. - fn emit_btc_gpr_imm8_32(&mut self, src: u8, dst: GPR) { + fn emit_btc_gpr_imm8_32(&mut self, _src: u8, _dst: GPR) { unimplemented!(); } - fn emit_btc_gpr_imm8_64(&mut self, src: u8, dst: GPR) { + fn emit_btc_gpr_imm8_64(&mut self, _src: u8, _dst: GPR) { unimplemented!(); } - fn emit_cmovae_gpr_32(&mut self, src: GPR, dst: GPR) { + fn emit_cmovae_gpr_32(&mut self, _src: GPR, _dst: GPR) { unimplemented!(); } - fn emit_cmovae_gpr_64(&mut self, src: GPR, dst: GPR) { + fn emit_cmovae_gpr_64(&mut self, _src: GPR, _dst: GPR) { unimplemented!(); } - fn emit_ucomiss(&mut self, src: XMMOrMemory, dst: XMM) { + fn emit_ucomiss(&mut self, _src: XMMOrMemory, _dst: XMM) { unimplemented!(); } - fn emit_ucomisd(&mut self, src: XMMOrMemory, dst: XMM) { + fn emit_ucomisd(&mut self, _src: XMMOrMemory, _dst: XMM) { unimplemented!(); } - fn emit_cvttss2si_32(&mut self, src: XMMOrMemory, dst: GPR) { + fn emit_cvttss2si_32(&mut self, _src: XMMOrMemory, _dst: GPR) { unimplemented!(); } - fn emit_cvttss2si_64(&mut self, src: XMMOrMemory, dst: GPR) { + fn emit_cvttss2si_64(&mut self, _src: XMMOrMemory, _dst: GPR) { unimplemented!(); } - fn emit_cvttsd2si_32(&mut self, src: XMMOrMemory, dst: GPR) { + fn emit_cvttsd2si_32(&mut self, _src: XMMOrMemory, _dst: GPR) { unimplemented!(); } - fn emit_cvttsd2si_64(&mut self, src: XMMOrMemory, dst: GPR) { + fn emit_cvttsd2si_64(&mut self, _src: XMMOrMemory, _dst: GPR) { unimplemented!(); } - fn emit_vcvtsi2ss_32(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { + fn emit_vcvtsi2ss_32(&mut self, _src1: XMM, _src2: GPROrMemory, _dst: XMM) { unimplemented!(); } - fn emit_vcvtsi2ss_64(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { + fn emit_vcvtsi2ss_64(&mut self, _src1: XMM, _src2: GPROrMemory, _dst: XMM) { unimplemented!(); } - fn emit_vcvtsi2sd_32(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { + fn emit_vcvtsi2sd_32(&mut self, _src1: XMM, _src2: GPROrMemory, _dst: XMM) { unimplemented!(); } - fn emit_vcvtsi2sd_64(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { + fn emit_vcvtsi2sd_64(&mut self, _src1: XMM, _src2: GPROrMemory, _dst: XMM) { unimplemented!(); } - fn emit_test_gpr_64(&mut self, reg: GPR) { + fn emit_test_gpr_64(&mut self, _reg: GPR) { unimplemented!(); } From f9bef056bad84c94febd8e498794c82192d61680 Mon Sep 17 00:00:00 2001 From: Mark McCaskey <5770194+MarkMcCaskey@users.noreply.github.com> Date: Tue, 19 Nov 2019 09:48:51 -0800 Subject: [PATCH 182/342] Fix github issue link in feature matrix --- 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 81602762bbc..54aa9810b43 100644 --- a/docs/feature_matrix.md +++ b/docs/feature_matrix.md @@ -18,7 +18,7 @@ | - | :-: | :-: | :-: | | Cranelift Backend | ✅ | ✅ | ✅ | | LLVM Backend | ✅ | ✅ | ✅ | -| Singlepass Backend | [#347](https://github.com/wasmerio/wasmer/issues/347) | ✅ | ✅ | +| Singlepass Backend | ✅ | ✅ | [#347](https://github.com/wasmerio/wasmer/issues/347) | | WASI | ✅ | ✅ | ✅* | * `poll_fd` is not fully implemented for Windows yet From 93f096b726990c93bd865d7856255c20735a4d11 Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 20 Nov 2019 01:52:33 +0800 Subject: [PATCH 183/342] Fix lint errors when singlepass is disabled. --- src/bin/wasmer.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 5c308f42dda..03e19f7eb5f 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -860,27 +860,27 @@ fn validate(validate: Validate) { } } -fn get_compiler_by_backend(backend: Backend, opts: &Run) -> Option> { - use wasmer_runtime_core::codegen::MiddlewareChain; - let opts = opts.clone(); - let middlewares_gen = move || { - let mut middlewares = MiddlewareChain::new(); - if opts.call_trace { - use wasmer_middleware_common::call_trace::CallTrace; - middlewares.push(CallTrace::new()); - } - if opts.block_trace { - use wasmer_middleware_common::block_trace::BlockTrace; - middlewares.push(BlockTrace::new()); - } - middlewares - }; - +fn get_compiler_by_backend(backend: Backend, _opts: &Run) -> Option> { Some(match backend { #[cfg(feature = "backend-singlepass")] Backend::Singlepass => { use wasmer_runtime_core::codegen::StreamingCompiler; use wasmer_singlepass_backend::ModuleCodeGenerator as SinglePassMCG; + use wasmer_runtime_core::codegen::MiddlewareChain; + + let opts = _opts.clone(); + let middlewares_gen = move || { + let mut middlewares = MiddlewareChain::new(); + if opts.call_trace { + use wasmer_middleware_common::call_trace::CallTrace; + middlewares.push(CallTrace::new()); + } + if opts.block_trace { + use wasmer_middleware_common::block_trace::BlockTrace; + middlewares.push(BlockTrace::new()); + } + middlewares + }; let c: StreamingCompiler = StreamingCompiler::new(middlewares_gen); From 28ebe5f7585dbba6cdf19e967cb7475f34d4c4e9 Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 20 Nov 2019 01:56:13 +0800 Subject: [PATCH 184/342] Rustfmt --- src/bin/wasmer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index b4f83a68118..6eb4827450d 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -869,9 +869,9 @@ fn get_compiler_by_backend(backend: Backend, _opts: &Run) -> Option { + use wasmer_runtime_core::codegen::MiddlewareChain; use wasmer_runtime_core::codegen::StreamingCompiler; use wasmer_singlepass_backend::ModuleCodeGenerator as SinglePassMCG; - use wasmer_runtime_core::codegen::MiddlewareChain; let opts = _opts.clone(); let middlewares_gen = move || { From 0c7545ded7889be4696fc7838dc8e7ecbe30989b Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 20 Nov 2019 02:09:32 +0800 Subject: [PATCH 185/342] Tell dynasm we are generating x64 code in `emitter_x64`. --- lib/singlepass-backend/src/emitter_x64.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index 25cb30bd7ae..0a6c04d08d6 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -2,6 +2,13 @@ use dynasmrt::{x64::Assembler, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLa use wasmer_runtime_core::backend::InlineBreakpointType; pub use wasmer_runtime_core::state::x64_decl::{GPR, XMM}; +fn _dummy(_a: &Assembler) { + dynasm!( + _a + ; .arch x64 + ); +} + #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum Location { Imm8(u8), From 8efa8e299ca296b399658c6d44235db55cae68d2 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Tue, 19 Nov 2019 13:53:36 -0800 Subject: [PATCH 186/342] Improved README instructions --- README.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 98533edf91b..277b8a06964 100644 --- a/README.md +++ b/README.md @@ -167,15 +167,12 @@ nginx and Lua do not work on Windows - you can track the progress on [this issue 2. Install [Rust for Windows](https://win.rustup.rs) -3. Install [Python for Windows](https://www.python.org/downloads/release/python-2714/). The Windows x86-64 MSI installer is fine. - Make sure to enable "Add python.exe to Path" during installation. - -4. Install [Git for Windows](https://git-scm.com/download/win). Allow it to add `git.exe` to your PATH (default +3. Install [Git for Windows](https://git-scm.com/download/win). Allow it to add `git.exe` to your PATH (default settings for the installer are fine). -5. Install [CMake](https://cmake.org/download/). Ensure CMake is in your PATH. +4. Install [CMake](https://cmake.org/download/). Ensure CMake is in your PATH. -6. Install [LLVM 8.0](https://prereleases.llvm.org/win-snapshots/LLVM-8.0.0-r351033-win64.exe) +5. Install [LLVM 8.0](https://prereleases.llvm.org/win-snapshots/LLVM-8.0.0-r351033-win64.exe)

From bd5884204117b5f76ce46bb1073ce8ed511edfa0 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Tue, 19 Nov 2019 23:38:50 -0600 Subject: [PATCH 187/342] Refactor excludes and add target_arch option --- lib/spectests/tests/excludes.txt | 4 +- lib/spectests/tests/spectest.rs | 254 +++++++++++++++++++++++++------ 2 files changed, 210 insertions(+), 48 deletions(-) diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index 62802769383..45310f2e8ff 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -12,10 +12,12 @@ # Star line allows skipping an entire wast file # clif:skip:simd.wast:* # -# Excludes can also contain platform +# Excludes can also contain target family # clif:skip:data.wast:172:windows # clif:skip:data.wast:172:unix # +# Or target arch +# singlepass:skip:atomic.wast:*:*:aarch64 # Cranelift clif:skip:atomic.wast:* # Threads not implemented diff --git a/lib/spectests/tests/spectest.rs b/lib/spectests/tests/spectest.rs index 299971ee154..9bb6f631c7c 100644 --- a/lib/spectests/tests/spectest.rs +++ b/lib/spectests/tests/spectest.rs @@ -18,6 +18,7 @@ mod tests { // TODO Files could be run with multiple threads // TODO Allow running WAST &str directly (E.g. for use outside of spectests) + use std::collections::HashSet; use std::sync::{Arc, Mutex}; struct SpecFailure { @@ -46,15 +47,14 @@ mod tests { pub fn add_failure( &mut self, failure: SpecFailure, - testkey: &str, - excludes: &HashMap, + _testkey: &str, + excludes: &Vec, + line: u64, ) { - if excludes.contains_key(testkey) { - self.allowed_failure += 1; - return; - } - let platform_key = format!("{}:{}", testkey, get_platform()); - if excludes.contains_key(&platform_key) { + if excludes + .iter() + .any(|e| e.line_matches(line) && e.exclude_kind == ExcludeKind::Fail) + { self.allowed_failure += 1; return; } @@ -104,15 +104,113 @@ mod tests { } #[cfg(unix)] - fn get_platform() -> &'static str { + fn get_target_family() -> &'static str { "unix" } #[cfg(windows)] - fn get_platform() -> &'static str { + fn get_target_family() -> &'static str { "windows" } + fn get_target_arch() -> &'static str { + if cfg!(target_arch = "x86_64") { + "x86_64" + } else if cfg!(target_arch = "aarch64") { + "aarch64" + } else if cfg!(target_arch = "x86") { + "x86" + } else if cfg!(target_arch = "mips") { + "mips" + } else if cfg!(target_arch = "powerpc") { + "powerpc" + } else if cfg!(target_arch = "powerpc64") { + "powerpc64" + } else if cfg!(target_arch = "arm") { + "arm" + } else { + panic!("unknown target arch") + } + } + + // clif:skip:data.wast:172:unix:x86 + #[allow(dead_code)] + struct Exclude { + backend: Option, + exclude_kind: ExcludeKind, + file: String, + line: Option, + target_family: Option, + target_arch: Option, + } + + impl Exclude { + fn line_matches(&self, value: u64) -> bool { + self.line.is_none() || self.line.unwrap() == value + } + + fn line_exact_match(&self, value: u64) -> bool { + self.line.is_some() && self.line.unwrap() == value + } + + fn matches_backend(&self, value: &str) -> bool { + self.backend.is_none() || self.backend.as_ref().unwrap() == value + } + + fn matches_target_family(&self, value: &str) -> bool { + self.target_family.is_none() || self.target_family.as_ref().unwrap() == value + } + + fn matches_target_arch(&self, value: &str) -> bool { + self.target_arch.is_none() || self.target_arch.as_ref().unwrap() == value + } + + fn from( + backend: &str, + exclude_kind: &str, + file: &str, + line: &str, + target_family: &str, + target_arch: &str, + ) -> Exclude { + let backend: Option = match backend { + "*" => None, + "clif" => Some("clif".to_string()), + "singlepass" => Some("singlepass".to_string()), + "llvm" => Some("llvm".to_string()), + _ => panic!("backend {:?} not recognized", backend), + }; + let exclude_kind = match exclude_kind { + "skip" => ExcludeKind::Skip, + "fail" => ExcludeKind::Fail, + _ => panic!("exclude kind {:?} not recognized", exclude_kind), + }; + let line = match line { + "*" => None, + _ => Some( + line.parse::() + .expect(&format!("expected * or int: {:?}", line)), + ), + }; + let target_family = match target_family { + "*" => None, + _ => Some(target_family.to_string()), + }; + let target_arch = match target_arch { + "*" => None, + _ => Some(target_arch.to_string()), + }; + Exclude { + backend, + exclude_kind, + file: file.to_string(), + line, + target_family, + target_arch, + } + } + } + #[cfg(not(any(feature = "llvm", feature = "clif", feature = "singlepass")))] fn get_compiler_name() -> &'static str { panic!("compiler not specified, activate a compiler via features"); @@ -160,7 +258,8 @@ mod tests { fn parse_and_run( path: &PathBuf, - excludes: &HashMap, + file_excludes: &HashSet, + excludes: &HashMap>, ) -> Result { let mut test_report = TestReport { failures: vec![], @@ -171,15 +270,9 @@ mod tests { let filename = path.file_name().unwrap().to_str().unwrap(); let source = fs::read(&path).unwrap(); - let backend = get_compiler_name(); - let platform = get_platform(); - let star_key = format!("{}:{}:*", backend, filename); - let platform_star_key = format!("{}:{}:*:{}", backend, filename, platform); - if (excludes.contains_key(&star_key) && *excludes.get(&star_key).unwrap() == Exclude::Skip) - || (excludes.contains_key(&platform_star_key) - && *excludes.get(&platform_star_key).unwrap() == Exclude::Skip) - { + // Entire file is excluded by line * and skip + if file_excludes.contains(filename) { return Ok(test_report); } @@ -198,21 +291,27 @@ mod tests { let mut registered_modules: HashMap>> = HashMap::new(); // + let empty_excludes = vec![]; + let excludes = if excludes.contains_key(filename) { + excludes.get(filename).unwrap() + } else { + &empty_excludes + }; + + let backend = get_compiler_name(); while let Some(Command { kind, line }) = parser.next().map_err(|e| format!("Parse err: {:?}", e))? { let test_key = format!("{}:{}:{}", backend, filename, line); - let test_platform_key = format!("{}:{}:{}:{}", backend, filename, line, platform); // Use this line to debug which test is running println!("Running test: {}", test_key); - if (excludes.contains_key(&test_key) - && *excludes.get(&test_key).unwrap() == Exclude::Skip) - || (excludes.contains_key(&test_platform_key) - && *excludes.get(&test_platform_key).unwrap() == Exclude::Skip) + // Skip tests that match this line + if excludes + .iter() + .any(|e| e.line_exact_match(line) && e.exclude_kind == ExcludeKind::Skip) { - // println!("Skipping test: {}", test_key); continue; } @@ -251,6 +350,7 @@ mod tests { }, &test_key, excludes, + line, ); instance = None; } @@ -290,6 +390,7 @@ mod tests { }, &test_key, excludes, + line, ); } else { let call_result = maybe_call_result.unwrap(); @@ -304,6 +405,7 @@ mod tests { }, &test_key, excludes, + line, ); } Ok(values) => { @@ -320,7 +422,7 @@ mod tests { "result {:?} ({:?}) does not match expected {:?} ({:?})", v, to_hex(v.clone()), expected_value, to_hex(expected_value.clone()) ), - }, &test_key, excludes); + }, &test_key, excludes, line); } else { test_report.count_passed(); } @@ -350,6 +452,7 @@ mod tests { }, &test_key, excludes, + line, ); } else { let export: Export = maybe_call_result.unwrap(); @@ -373,6 +476,7 @@ mod tests { }, &test_key, excludes, + line, ); } } @@ -386,6 +490,7 @@ mod tests { }, &test_key, excludes, + line, ); } } @@ -416,6 +521,7 @@ mod tests { }, &test_key, excludes, + line, ); } else { let call_result = maybe_call_result.unwrap(); @@ -430,6 +536,7 @@ mod tests { }, &test_key, excludes, + line, ); } Ok(values) => { @@ -453,6 +560,7 @@ mod tests { }, &test_key, excludes, + line, ); } } @@ -484,6 +592,7 @@ mod tests { }, &test_key, excludes, + line, ); } else { let call_result = maybe_call_result.unwrap(); @@ -498,6 +607,7 @@ mod tests { }, &test_key, excludes, + line, ); } Ok(values) => { @@ -521,6 +631,7 @@ mod tests { }, &test_key, excludes, + line, ); } } @@ -552,6 +663,7 @@ mod tests { }, &test_key, excludes, + line, ); } else { let call_result = maybe_call_result.unwrap(); @@ -569,6 +681,7 @@ mod tests { }, &test_key, excludes, + line, ); } CallError::Runtime(r) => { @@ -590,6 +703,7 @@ mod tests { }, &test_key, excludes, + line, ); } } @@ -606,6 +720,7 @@ mod tests { }, &test_key, excludes, + line, ); } } @@ -649,6 +764,7 @@ mod tests { }, &test_key, excludes, + line, ); } } @@ -662,6 +778,7 @@ mod tests { }, &test_key, excludes, + line, ); } } @@ -704,6 +821,7 @@ mod tests { }, &test_key, excludes, + line, ); } } @@ -717,6 +835,7 @@ mod tests { }, &test_key, excludes, + line, ); } } @@ -755,6 +874,7 @@ mod tests { }, &test_key, excludes, + line, ); } }; @@ -786,6 +906,7 @@ mod tests { }, &test_key, excludes, + line, ); } else { let call_result = maybe_call_result.unwrap(); @@ -807,6 +928,7 @@ mod tests { }, &test_key, excludes, + line, ); } } @@ -845,6 +967,7 @@ mod tests { }, &test_key, excludes, + line, ); } Ok(result) => match result { @@ -860,6 +983,7 @@ mod tests { }, &test_key, excludes, + line, ); } Err(e) => match e { @@ -876,6 +1000,7 @@ mod tests { }, &test_key, excludes, + line, ); } }, @@ -909,6 +1034,7 @@ mod tests { }, &test_key, excludes, + line, ); } } @@ -934,6 +1060,7 @@ mod tests { }, &test_key, excludes, + line, ); } else { let call_result = maybe_call_result.unwrap(); @@ -948,6 +1075,7 @@ mod tests { }, &test_key, excludes, + line, ); } Ok(_values) => { @@ -1105,7 +1233,7 @@ mod tests { } #[derive(Debug, Copy, Clone, PartialEq, Eq)] - enum Exclude { + enum ExcludeKind { Skip, Fail, } @@ -1115,13 +1243,18 @@ mod tests { use std::io::{BufRead, BufReader}; /// Reads the excludes.txt file into a hash map - fn read_excludes() -> HashMap { + fn read_excludes() -> (HashMap>, HashSet) { let mut excludes_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); excludes_path.push("tests"); excludes_path.push("excludes.txt"); let input = File::open(excludes_path).unwrap(); let buffered = BufReader::new(input); let mut result = HashMap::new(); + let mut file_excludes = HashSet::new(); + let current_backend = get_compiler_name(); + let current_target_family = get_target_family(); + let current_target_arch = get_target_arch(); + for line in buffered.lines() { let mut line = line.unwrap(); if line.trim().is_empty() || line.starts_with("#") { @@ -1136,26 +1269,53 @@ mod tests { // ::: let split: Vec<&str> = line.trim().split(':').collect(); - let kind = match *split.get(1).unwrap() { - "skip" => Exclude::Skip, - "fail" => Exclude::Fail, - _ => panic!("unknown exclude kind"), - }; - let has_platform = split.len() > 4; - - let backend = split.get(0).unwrap(); - let testfile = split.get(2).unwrap(); - let line = split.get(3).unwrap(); - let key = if has_platform { - let platform = split.get(4).unwrap(); - format!("{}:{}:{}:{}", backend, testfile, line, platform) - } else { - format!("{}:{}:{}", backend, testfile, line) + let file = *split.get(2).unwrap(); + let exclude = match split.len() { + 0..=3 => panic!("expected at least 4 exclude conditions"), + 4 => Exclude::from( + *split.get(0).unwrap(), + *split.get(1).unwrap(), + *split.get(2).unwrap(), + *split.get(3).unwrap(), + "*", + "*", + ), + 5 => Exclude::from( + *split.get(0).unwrap(), + *split.get(1).unwrap(), + *split.get(2).unwrap(), + *split.get(3).unwrap(), + *split.get(4).unwrap(), + "*", + ), + 6 => Exclude::from( + *split.get(0).unwrap(), + *split.get(1).unwrap(), + *split.get(2).unwrap(), + *split.get(3).unwrap(), + *split.get(4).unwrap(), + *split.get(5).unwrap(), + ), + _ => panic!("too many exclude conditions {}", split.len()), }; - result.insert(key, kind); + + if exclude.matches_backend(current_backend) + && exclude.matches_target_family(current_target_family) + && exclude.matches_target_arch(current_target_arch) + { + // Skip the whole file for line * and skip + if exclude.line.is_none() && exclude.exclude_kind == ExcludeKind::Skip { + file_excludes.insert(file.to_string()); + } + + if !result.contains_key(file) { + result.insert(file.to_string(), vec![]); + } + result.get_mut(file).unwrap().push(exclude); + } } } - result + (result, file_excludes) } #[test] @@ -1163,7 +1323,7 @@ mod tests { let mut success = true; let mut test_reports = vec![]; - let excludes = read_excludes(); + let (excludes, file_excludes) = read_excludes(); let mut glob_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); glob_path.push("spectests"); @@ -1173,7 +1333,7 @@ mod tests { for entry in glob(glob_str).expect("Failed to read glob pattern") { match entry { Ok(wast_path) => { - let result = parse_and_run(&wast_path, &excludes); + let result = parse_and_run(&wast_path, &file_excludes, &excludes); match result { Ok(test_report) => { if test_report.has_failures() { From dfe7c0d764a953e079cb35b62d2907bccb4b8c19 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 20 Nov 2019 13:27:18 +0100 Subject: [PATCH 188/342] fix(runtime-c-api) Add support for GNUC when defining `ARCH_X86_64`. `ARCH_X86_64` is correctly defined for GCC or clang, but gnuc was missing. This patch fixes that. --- lib/runtime-c-api/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime-c-api/build.rs b/lib/runtime-c-api/build.rs index 7750b00813d..5897001b043 100644 --- a/lib/runtime-c-api/build.rs +++ b/lib/runtime-c-api/build.rs @@ -22,7 +22,7 @@ fn main() { #endif #endif -#if defined(GCC) || defined(__clang__) +#if defined(GCC) || defined(__GNUC__) || defined(__clang__) #if defined(__x86_64__) #define ARCH_X86_64 #endif From 9468e229f4f2c968955c16c0eb6fa016b0f19154 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 20 Nov 2019 13:30:02 +0100 Subject: [PATCH 189/342] chore(runtime-c-api) Update header files. --- lib/runtime-c-api/wasmer.h | 2 +- lib/runtime-c-api/wasmer.hh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 836a41df215..40a265cff3b 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -8,7 +8,7 @@ #endif #endif -#if defined(GCC) || defined(__clang__) +#if defined(GCC) || defined(__GNUC__) || defined(__clang__) #if defined(__x86_64__) #define ARCH_X86_64 #endif diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 79c350d6080..b437edd4be0 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -8,7 +8,7 @@ #endif #endif -#if defined(GCC) || defined(__clang__) +#if defined(GCC) || defined(__GNUC__) || defined(__clang__) #if defined(__x86_64__) #define ARCH_X86_64 #endif From 6ba3d1c5bc47bbba8303cd22039ce810f85c0a26 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 20 Nov 2019 13:32:31 +0100 Subject: [PATCH 190/342] doc(changelog) Add #987. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ed6bfc742f..40a600caf82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## **[Unreleased]** +- [#987](https://github.com/wasmerio/wasmer/pull/987) Fix `runtime-c-api` header files when compiled by gnuc. + ## 0.10.2 - 2019-11-18 - [#968](https://github.com/wasmerio/wasmer/pull/968) Added `--invoke` option to the command From 1685455eb64bf1f770cbebe861e3f39d72800bef Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 14:50:37 -0800 Subject: [PATCH 191/342] Allow to do wasmer execution without the `run` argument --- src/bin/wasmer.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 7af5df3e258..012758504e1 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -842,7 +842,20 @@ fn get_compiler_by_backend(backend: Backend) -> Option> { } fn main() { - let options = CLIOptions::from_args(); + let options = { + let args: Vec = env::args().into_iter().filter(|x| !x.starts_with("-")).collect(); + match args.get(1).map_or("", |s| &s) { + // Default + "run" | "cache" | "validate" | "self_update" | "" => { + CLIOptions::from_args() + } + // Wasmer trying to run a file directly + _ => { + let run_options = Run::from_args(); + CLIOptions::Run(run_options) + } + } + }; match options { CLIOptions::Run(options) => run(options), #[cfg(not(target_os = "windows"))] From cb7fcb94522d8b9b43d9322800553d81578555d7 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 20 Nov 2019 14:59:55 -0800 Subject: [PATCH 192/342] Simplify default run logic --- src/bin/wasmer.rs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 012758504e1..ef3ea2d9eac 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -842,20 +842,8 @@ fn get_compiler_by_backend(backend: Backend) -> Option> { } fn main() { - let options = { - let args: Vec = env::args().into_iter().filter(|x| !x.starts_with("-")).collect(); - match args.get(1).map_or("", |s| &s) { - // Default - "run" | "cache" | "validate" | "self_update" | "" => { - CLIOptions::from_args() - } - // Wasmer trying to run a file directly - _ => { - let run_options = Run::from_args(); - CLIOptions::Run(run_options) - } - } - }; + let options = StructOpt::from_iter_safe(env::args()) + .unwrap_or_else(|_| CLIOptions::Run(Run::from_args())); match options { CLIOptions::Run(options) => run(options), #[cfg(not(target_os = "windows"))] From 4a84441ab0b879604c8db3a3beeabcdcc93ae2a4 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 20 Nov 2019 15:41:33 -0800 Subject: [PATCH 193/342] Run WASI C API tests based on feature; prevent cmake caching --- lib/runtime-c-api/tests/CMakeLists.txt | 14 ++++++++++---- .../tests/runtime_c_api_tests.rs | 9 ++++++++- lib/runtime-c-api/tests/test-import-object | Bin 14932 -> 19040 bytes .../tests/test-wasi-import-object | Bin 15612 -> 0 bytes 4 files changed, 18 insertions(+), 5 deletions(-) delete mode 100755 lib/runtime-c-api/tests/test-wasi-import-object diff --git a/lib/runtime-c-api/tests/CMakeLists.txt b/lib/runtime-c-api/tests/CMakeLists.txt index d8f206c4939..e4a573e6386 100644 --- a/lib/runtime-c-api/tests/CMakeLists.txt +++ b/lib/runtime-c-api/tests/CMakeLists.txt @@ -7,7 +7,6 @@ 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) @@ -19,6 +18,10 @@ add_executable(test-validate test-validate.c) add_executable(test-context test-context.c) add_executable(test-module-import-instantiate test-module-import-instantiate.c) +if (DEFINED WASI_TESTS) + add_executable(test-wasi-import-object test-wasi-import-object.c) +endif() + find_library( WASMER_LIB NAMES libwasmer_runtime_c_api.dylib libwasmer_runtime_c_api.so wasmer_runtime_c_api.dll PATHS ${CMAKE_SOURCE_DIR}/../../../target/release/ @@ -64,9 +67,12 @@ 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) + +if (DEFINED WASI_TESTS) + 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) +endif() target_link_libraries(test-instantiate general ${WASMER_LIB}) target_compile_options(test-instantiate PRIVATE ${COMPILER_OPTIONS}) diff --git a/lib/runtime-c-api/tests/runtime_c_api_tests.rs b/lib/runtime-c-api/tests/runtime_c_api_tests.rs index 0e32577860f..ed414636374 100644 --- a/lib/runtime-c-api/tests/runtime_c_api_tests.rs +++ b/lib/runtime-c-api/tests/runtime_c_api_tests.rs @@ -4,7 +4,14 @@ use std::process::Command; fn test_c_api() { let project_tests_dir = concat!(env!("CARGO_MANIFEST_DIR"), "/tests"); - run_command("cmake", project_tests_dir, vec!["."]); + let cmake_args = vec![ + ".", + #[cfg(feature = "wasi")] + "-DWASI_TESTS=ON", + ]; + // we use -f so it doesn't fail if the fiel doesn't exist + run_command("rm", project_tests_dir, vec!["-f", "CMakeCache.txt"]); + run_command("cmake", project_tests_dir, cmake_args); run_command("make", project_tests_dir, vec!["-Wdev", "-Werror=dev"]); run_command("make", project_tests_dir, vec!["test", "ARGS=\"-V\""]); } diff --git a/lib/runtime-c-api/tests/test-import-object b/lib/runtime-c-api/tests/test-import-object index 42e1496de5000443de925286aeb63b7aa2e67456..bb0a97db3c95f2045f3f2e76e4099a5dc7ac76c9 100755 GIT binary patch delta 1524 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 From 76e346b7080e3ef2a8e71cffaebf82a1916ce429 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 20 Nov 2019 15:50:46 -0800 Subject: [PATCH 194/342] Clean up from feedback, update changelog --- CHANGELOG.md | 1 + src/bin/wasmer.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40a600caf82..c658e024d3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## **[Unreleased]** +- [#990](https://github.com/wasmerio/wasmer/pull/990) Default wasmer CLI to `run`. Wasmer will now attempt to parse unrecognized command line options as if they were applied to the run command: `wasmer mywasm.wasm --dir=.` now works! - [#987](https://github.com/wasmerio/wasmer/pull/987) Fix `runtime-c-api` header files when compiled by gnuc. ## 0.10.2 - 2019-11-18 diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 5df7d5e5d40..26afcc03947 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -848,7 +848,7 @@ fn get_compiler_by_backend(backend: Backend) -> Option> { } fn main() { - let options = StructOpt::from_iter_safe(env::args()) + let options = CLIOptions::from_iter_safe(env::args()) .unwrap_or_else(|_| CLIOptions::Run(Run::from_args())); match options { CLIOptions::Run(options) => run(options), From fc733647ec169aeb6ef4a7896e0974d8b00b053e Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 20 Nov 2019 16:38:44 -0800 Subject: [PATCH 195/342] Add info in c api readme in the testing section --- lib/runtime-c-api/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/runtime-c-api/README.md b/lib/runtime-c-api/README.md index 8ce84a130d4..06e545bf739 100644 --- a/lib/runtime-c-api/README.md +++ b/lib/runtime-c-api/README.md @@ -105,6 +105,10 @@ int main() # Testing +Tests are run using the release build of the library. If you make +changes or compile with non-default features, please ensure you +rebuild in release mode for the tests to see the changes. + The tests can be run via `cargo test`, such as: ```sh From 70197c2e07d6df2179676bba0e977dcd03e66a2b Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 16:38:50 -0800 Subject: [PATCH 196/342] Update wapm-cli to latest version --- wapm-cli | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wapm-cli b/wapm-cli index c2da5cda3b8..3e9b1ea7b2d 160000 --- a/wapm-cli +++ b/wapm-cli @@ -1 +1 @@ -Subproject commit c2da5cda3b8f9cf7dcea144f8cabdf342f38a0bf +Subproject commit 3e9b1ea7b2d1ddae9de2e2ae6a2af03cdae0e385 From 274367b1527038236503724aaf7f9408a39bf70c Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 17:15:20 -0800 Subject: [PATCH 197/342] Fixed CLI arguments issue --- Cargo.lock | 1 + Cargo.toml | 1 + src/bin/wasmer.rs | 17 ++++++++++++++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 24fa874a31a..a20878c06a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1336,6 +1336,7 @@ name = "wasmer" version = "0.10.2" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", diff --git a/Cargo.toml b/Cargo.toml index 8724d91d4a3..5c48c6551d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ include = [ [dependencies] byteorder = "1.3" +clap="2.33.0" errno = "0.2" structopt = "0.3" wabt = "0.9.1" diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 26afcc03947..93add0a13ec 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -16,6 +16,7 @@ use std::io::Read; use std::path::PathBuf; use std::process::exit; use std::str::FromStr; +use clap; use std::collections::HashMap; use structopt::StructOpt; @@ -848,8 +849,22 @@ fn get_compiler_by_backend(backend: Backend) -> Option> { } fn main() { + // We try to run wasmer with the normal arguments. + // Eg. `wasmer ` + // In case that fails, we fallback trying the Run subcommand directly. + // Eg. `wasmer myfile.wasm --dir=.` let options = CLIOptions::from_iter_safe(env::args()) - .unwrap_or_else(|_| CLIOptions::Run(Run::from_args())); + .unwrap_or_else(|e| { + match e.kind { + // This fixes a issue that: + // 1. Shows the version twice when doing `wasmer -V` + // 2. Shows the run help (instead of normal help) when doing `wasmer --help` + clap::ErrorKind::VersionDisplayed | clap::ErrorKind::HelpDisplayed => { + e.exit() + } + _ => CLIOptions::Run(Run::from_args()) + } + }); match options { CLIOptions::Run(options) => run(options), #[cfg(not(target_os = "windows"))] From f0fc15a4aa1bff9025c295282cc9be6115037c33 Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 17:15:31 -0800 Subject: [PATCH 198/342] Updated WAPM CLI to to 0.4.1 --- wapm-cli | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wapm-cli b/wapm-cli index 3e9b1ea7b2d..3562d6dda52 160000 --- a/wapm-cli +++ b/wapm-cli @@ -1 +1 @@ -Subproject commit 3e9b1ea7b2d1ddae9de2e2ae6a2af03cdae0e385 +Subproject commit 3562d6dda52df526e6e1917dd33bb2454917ab9c From 8f625498197e439a01ee1745b555493242dcd720 Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 17:18:52 -0800 Subject: [PATCH 199/342] Added changes in CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c658e024d3a..c7b0088dc52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## **[Unreleased]** +- [#992](https://github.com/wasmerio/wasmer/pull/992) Updates WAPM version to 0.4.1, fix arguments issue introduced in #990 - [#990](https://github.com/wasmerio/wasmer/pull/990) Default wasmer CLI to `run`. Wasmer will now attempt to parse unrecognized command line options as if they were applied to the run command: `wasmer mywasm.wasm --dir=.` now works! - [#987](https://github.com/wasmerio/wasmer/pull/987) Fix `runtime-c-api` header files when compiled by gnuc. From a71b9519c453527145c2473e7f751e235b646142 Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 17:19:42 -0800 Subject: [PATCH 200/342] Fix lint issues --- src/bin/wasmer.rs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 93add0a13ec..966c6c0f67a 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -9,6 +9,7 @@ )] extern crate structopt; +use clap; use std::env; use std::fs::{read_to_string, File}; use std::io; @@ -16,7 +17,6 @@ use std::io::Read; use std::path::PathBuf; use std::process::exit; use std::str::FromStr; -use clap; use std::collections::HashMap; use structopt::StructOpt; @@ -853,18 +853,15 @@ fn main() { // Eg. `wasmer ` // In case that fails, we fallback trying the Run subcommand directly. // Eg. `wasmer myfile.wasm --dir=.` - let options = CLIOptions::from_iter_safe(env::args()) - .unwrap_or_else(|e| { - match e.kind { - // This fixes a issue that: - // 1. Shows the version twice when doing `wasmer -V` - // 2. Shows the run help (instead of normal help) when doing `wasmer --help` - clap::ErrorKind::VersionDisplayed | clap::ErrorKind::HelpDisplayed => { - e.exit() - } - _ => CLIOptions::Run(Run::from_args()) - } - }); + let options = CLIOptions::from_iter_safe(env::args()).unwrap_or_else(|e| { + match e.kind { + // This fixes a issue that: + // 1. Shows the version twice when doing `wasmer -V` + // 2. Shows the run help (instead of normal help) when doing `wasmer --help` + clap::ErrorKind::VersionDisplayed | clap::ErrorKind::HelpDisplayed => e.exit(), + _ => CLIOptions::Run(Run::from_args()), + } + }); match options { CLIOptions::Run(options) => run(options), #[cfg(not(target_os = "windows"))] From dc01afb3b5658d021929b349b6b79b10538f7494 Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 17:28:43 -0800 Subject: [PATCH 201/342] Use structopt clap instead of global clap --- Cargo.lock | 1 - Cargo.toml | 1 - src/bin/wasmer.rs | 3 +-- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a20878c06a8..24fa874a31a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1336,7 +1336,6 @@ name = "wasmer" version = "0.10.2" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", diff --git a/Cargo.toml b/Cargo.toml index 5c48c6551d1..8724d91d4a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,6 @@ include = [ [dependencies] byteorder = "1.3" -clap="2.33.0" errno = "0.2" structopt = "0.3" wabt = "0.9.1" diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 966c6c0f67a..36e0100d671 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -9,7 +9,6 @@ )] extern crate structopt; -use clap; use std::env; use std::fs::{read_to_string, File}; use std::io; @@ -19,7 +18,7 @@ use std::process::exit; use std::str::FromStr; use std::collections::HashMap; -use structopt::StructOpt; +use structopt::{clap, StructOpt}; use wasmer::*; use wasmer_clif_backend::CraneliftCompiler; From ef1713dd0b2372da17902d2a863f9337909af2e1 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 20 Nov 2019 18:28:58 -0800 Subject: [PATCH 202/342] Update install.sh --- install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/install.sh b/install.sh index a4fc2b841e6..0420aad329f 100755 --- a/install.sh +++ b/install.sh @@ -211,6 +211,7 @@ initArch() { case $ARCH in amd64) ARCH="amd64";; x86_64) ARCH="amd64";; + aarch64) ARCH="arm64";; # i386) ARCH="386";; *) printf "$red> The system architecture (${ARCH}) is not supported by this installation script.$reset\n"; exit 1;; esac From b8aee87d6e3a57b111c158dd21caaef5ece73db8 Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 19:11:33 -0800 Subject: [PATCH 203/342] Skip atomic tests for now in singlepass Aarch64 --- lib/spectests/tests/excludes.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index 45310f2e8ff..a2742b0dcc2 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -306,6 +306,8 @@ llvm:skip:simd_binaryen.wast:*:unix # Module - caught panic Any singlepass:skip:simd.wast:* # SIMD not implemented singlepass:skip:simd_binaryen.wast:* # SIMD not implemented +singlepass:skip:atomic.wast:*:*:aarch64 # Threads not yet supported on singlepass + singlepass:fail:address.wast:192 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:address.wast:194 # AssertTrap - expected trap, got [] singlepass:fail:address.wast:195 # AssertTrap - expected trap, got [] From b3322a6c5c9f19e48628348449873879743f5956 Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 19:13:37 -0800 Subject: [PATCH 204/342] Move xxx.wat to the examples dir --- xxx.wat => examples/xxx.wat | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename xxx.wat => examples/xxx.wat (100%) diff --git a/xxx.wat b/examples/xxx.wat similarity index 100% rename from xxx.wat rename to examples/xxx.wat From cafad451755be408913262df459a515cacbcceb9 Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 19:13:59 -0800 Subject: [PATCH 205/342] Added make wapm command --- Makefile | 3 +++ azure-pipelines.yml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a19cc70a1e7..81b7f828af9 100644 --- a/Makefile +++ b/Makefile @@ -266,3 +266,6 @@ dep-graph: docs: cargo doc --features=backend-singlepass,backend-llvm,wasi,managed + +wapm: + cargo build --release --manifest-path wapm-cli/Cargo.toml --features "telemetry update-notifications" diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 23f806dca1e..720115f1828 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -123,7 +123,7 @@ jobs: displayName: Build (Windows) condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) - bash: | - cargo build --release --manifest-path wapm-cli/Cargo.toml --features "telemetry update-notifications" + make wapm displayName: Build WAPM condition: | eq(variables['Build.SourceBranch'], 'refs/heads/master') From 27b17893d8e3eb3691d787f7b1d9abaccf895bb6 Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 19:14:29 -0800 Subject: [PATCH 206/342] Move popcnt to examples --- popcnt.wat => examples/popcnt.wat | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename popcnt.wat => examples/popcnt.wat (100%) diff --git a/popcnt.wat b/examples/popcnt.wat similarity index 100% rename from popcnt.wat rename to examples/popcnt.wat From e5905c9b794aa0ece1722cfae6639cfe345471ca Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 19:34:27 -0800 Subject: [PATCH 207/342] Added support for the aarch64/arm64 in the scripts --- install.sh | 1 + scripts/binary-name.sh | 2 ++ 2 files changed, 3 insertions(+) diff --git a/install.sh b/install.sh index 0420aad329f..e6c874e2a0e 100755 --- a/install.sh +++ b/install.sh @@ -208,6 +208,7 @@ initArch() { printf "$cyan> Using WASMER_ARCH ($WASMER_ARCH).$reset\n" ARCH="$WASMER_ARCH" fi + # If you modify this list, please also modify scripts/binary-name.sh case $ARCH in amd64) ARCH="amd64";; x86_64) ARCH="amd64";; diff --git a/scripts/binary-name.sh b/scripts/binary-name.sh index 4ac8ef8e36b..0245690b726 100755 --- a/scripts/binary-name.sh +++ b/scripts/binary-name.sh @@ -5,9 +5,11 @@ initArch() { if [ -n "$WASMER_ARCH" ]; then ARCH="$WASMER_ARCH" fi + # If you modify this list, please also modify install.sh case $ARCH in amd64) ARCH="amd64";; x86_64) ARCH="amd64";; + aarch64) ARCH="arm64";; i386) ARCH="386";; *) echo "Architecture ${ARCH} is not supported by this installation script"; exit 1;; esac From c53199830fe99779f0f1425ac1c5a54c858402ec Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 19:36:34 -0800 Subject: [PATCH 208/342] Try to generate an arm release on the travis script --- .travis.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.travis.yml b/.travis.yml index 4690731fd6f..9702f83b823 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,20 @@ rust: script: - make spectests-singlepass + - make release-singlepass + - make wapm + - make build-install + - cp ./wasmer.tar.gz ./artifacts/$(./scripts/binary-name.sh) + +stage: GitHub Release + script: echo "Deploying to GitHub releases ..." + deploy: + provider: releases + file_glob: true + file: artifacts/* + api_key: $GITHUB_OAUTH_TOKEN + # This is set to the previous artifacts are not deleted by travis + skip_cleanup: true addons: apt: From 46f43bf6ee56d49a4ea7fbde6479b19cd964def4 Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 19:43:02 -0800 Subject: [PATCH 209/342] Fix travis config --- .travis.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9702f83b823..e7844e4086c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,15 +12,13 @@ script: - make build-install - cp ./wasmer.tar.gz ./artifacts/$(./scripts/binary-name.sh) -stage: GitHub Release - script: echo "Deploying to GitHub releases ..." - deploy: - provider: releases - file_glob: true - file: artifacts/* - api_key: $GITHUB_OAUTH_TOKEN - # This is set to the previous artifacts are not deleted by travis - skip_cleanup: true +deploy: + provider: releases + file_glob: true + file: artifacts/* + api_key: $GITHUB_OAUTH_TOKEN + # This is set to the previous artifacts are not deleted by travis + skip_cleanup: true addons: apt: From a4b1b9ecf1c0b0f9272ce64129f37c72ee709117 Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 20:04:47 -0800 Subject: [PATCH 210/342] Trying to improve Travis build script --- .travis.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.travis.yml b/.travis.yml index e7844e4086c..1feb660ae4d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,13 +5,36 @@ language: rust rust: - nightly +cache: + directories: + - /home/travis/.sccache/ + script: + # Sccache + - curl -L https://github.com/mozilla/sccache/releases/download/0.2.10/sccache-0.2.10-x86_64-unknown-linux-musl.tar.gz | tar xzf - + - export RUSTC_WRAPPER=`pwd`/sccache-0.2.10-x86_64-unknown-linux-musl/sccache + - mkdir -p /home/travis/.sccache/ + - export SCCACHE_DIR="/home/travis/.sccache/" + - SCCACHE_ERROR_LOG=`pwd`/sccache.log RUST_LOG=debug $RUSTC_WRAPPER --start-server + - $RUSTC_WRAPPER -s + + # Tests - make spectests-singlepass + + # Release - make release-singlepass - make wapm - make build-install + - mkdir -p artifacts - cp ./wasmer.tar.gz ./artifacts/$(./scripts/binary-name.sh) +before_deploy: + # Set up git user name and tag this commit + - git config --local user.name "Syrus Akbary" + - git config --local user.email "syrus@wasmer.io" + - export TRAVIS_TAG="0.10.2" + - git tag $TRAVIS_TAG + deploy: provider: releases file_glob: true From 6a68ff76f4457fc3ca4b0f75848ccdc0062a8ba9 Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 20:12:48 -0800 Subject: [PATCH 211/342] Trying to fix sccache in arm --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1feb660ae4d..96a36aefa21 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,8 +11,10 @@ cache: script: # Sccache - - curl -L https://github.com/mozilla/sccache/releases/download/0.2.10/sccache-0.2.10-x86_64-unknown-linux-musl.tar.gz | tar xzf - - - export RUSTC_WRAPPER=`pwd`/sccache-0.2.10-x86_64-unknown-linux-musl/sccache + # - curl -L https://github.com/mozilla/sccache/releases/download/0.2.10/sccache-0.2.10-x86_64-unknown-linux-musl.tar.gz | tar xzf - + # - export RUSTC_WRAPPER=`pwd`/sccache-0.2.10-x86_64-unknown-linux-musl/sccache + - cargo install sccache + - export RUSTC_WRAPPER=sccache - mkdir -p /home/travis/.sccache/ - export SCCACHE_DIR="/home/travis/.sccache/" - SCCACHE_ERROR_LOG=`pwd`/sccache.log RUST_LOG=debug $RUSTC_WRAPPER --start-server From d0437db61da8ae0875b0d6177e27deb34f97f5ec Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 20:21:23 -0800 Subject: [PATCH 212/342] Iterating on Travis --- .travis.yml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 96a36aefa21..9888b699fb5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,12 +8,13 @@ rust: cache: directories: - /home/travis/.sccache/ + - /home/travis/.cargo/bin/sccache script: # Sccache # - curl -L https://github.com/mozilla/sccache/releases/download/0.2.10/sccache-0.2.10-x86_64-unknown-linux-musl.tar.gz | tar xzf - # - export RUSTC_WRAPPER=`pwd`/sccache-0.2.10-x86_64-unknown-linux-musl/sccache - - cargo install sccache + - command -v sccache >/dev/null 2>&1 || cargo install sccache - export RUSTC_WRAPPER=sccache - mkdir -p /home/travis/.sccache/ - export SCCACHE_DIR="/home/travis/.sccache/" @@ -37,13 +38,13 @@ before_deploy: - export TRAVIS_TAG="0.10.2" - git tag $TRAVIS_TAG -deploy: - provider: releases - file_glob: true - file: artifacts/* - api_key: $GITHUB_OAUTH_TOKEN - # This is set to the previous artifacts are not deleted by travis - skip_cleanup: true +# deploy: +# provider: releases +# file_glob: true +# file: artifacts/* +# api_key: $GITHUB_OAUTH_TOKEN +# # This is set to the previous artifacts are not deleted by travis +# skip_cleanup: true addons: apt: From 1e886e278d54fd45ba4fd2382f1f10601bebccfd Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 20:28:04 -0800 Subject: [PATCH 213/342] Trying to make cargo happy --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9888b699fb5..091b3535fdb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,8 +14,8 @@ script: # Sccache # - curl -L https://github.com/mozilla/sccache/releases/download/0.2.10/sccache-0.2.10-x86_64-unknown-linux-musl.tar.gz | tar xzf - # - export RUSTC_WRAPPER=`pwd`/sccache-0.2.10-x86_64-unknown-linux-musl/sccache - - command -v sccache >/dev/null 2>&1 || cargo install sccache - - export RUSTC_WRAPPER=sccache + - test -f /home/travis/.cargo/bin/sccache || cargo install sccache --force + - export RUSTC_WRAPPER=/home/travis/.cargo/bin/sccache - mkdir -p /home/travis/.sccache/ - export SCCACHE_DIR="/home/travis/.sccache/" - SCCACHE_ERROR_LOG=`pwd`/sccache.log RUST_LOG=debug $RUSTC_WRAPPER --start-server From 605fdc912b8fc4e36dca5a865411d1840c769d88 Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 20:42:17 -0800 Subject: [PATCH 214/342] Trying to fix installation --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 091b3535fdb..686d2472307 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,13 +8,13 @@ rust: cache: directories: - /home/travis/.sccache/ - - /home/travis/.cargo/bin/sccache + - /home/travis/.cargo/bin script: # Sccache # - curl -L https://github.com/mozilla/sccache/releases/download/0.2.10/sccache-0.2.10-x86_64-unknown-linux-musl.tar.gz | tar xzf - # - export RUSTC_WRAPPER=`pwd`/sccache-0.2.10-x86_64-unknown-linux-musl/sccache - - test -f /home/travis/.cargo/bin/sccache || cargo install sccache --force + - test -f /home/travis/.cargo/bin/sccache || cargo install sccache - export RUSTC_WRAPPER=/home/travis/.cargo/bin/sccache - mkdir -p /home/travis/.sccache/ - export SCCACHE_DIR="/home/travis/.sccache/" From 43a99cda91be6cf4898fd954476f2edcffd54ed9 Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 21:05:22 -0800 Subject: [PATCH 215/342] Trying to upload artifact to GH releases --- .travis.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 686d2472307..93441b39d90 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,13 +38,13 @@ before_deploy: - export TRAVIS_TAG="0.10.2" - git tag $TRAVIS_TAG -# deploy: -# provider: releases -# file_glob: true -# file: artifacts/* -# api_key: $GITHUB_OAUTH_TOKEN -# # This is set to the previous artifacts are not deleted by travis -# skip_cleanup: true +deploy: + provider: releases + file_glob: true + file: artifacts/* + api_key: $GITHUB_OAUTH_TOKEN + # This is set to the previous artifacts are not deleted by travis + skip_cleanup: true addons: apt: From 10aa6c8f3a7572f983f425d46b7e09fe31784878 Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 21:24:11 -0800 Subject: [PATCH 216/342] Allow deployment on branch --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 93441b39d90..b8b108e773b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ rust: cache: directories: - /home/travis/.sccache/ - - /home/travis/.cargo/bin + - /home/travis/.cargo/bin/ script: # Sccache @@ -45,6 +45,9 @@ deploy: api_key: $GITHUB_OAUTH_TOKEN # This is set to the previous artifacts are not deleted by travis skip_cleanup: true + on: + branch: feature/singlepass-aarch64 + addons: apt: From 4d973dad60e539a36802bca27705acf3e92a0755 Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 20 Nov 2019 22:16:58 -0800 Subject: [PATCH 217/342] =?UTF-8?q?Don=E2=80=99t=20try=20to=20create=20a?= =?UTF-8?q?=20new=20tag?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b8b108e773b..ab8b1c4f2df 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,7 +36,7 @@ before_deploy: - git config --local user.name "Syrus Akbary" - git config --local user.email "syrus@wasmer.io" - export TRAVIS_TAG="0.10.2" - - git tag $TRAVIS_TAG + # - git tag $TRAVIS_TAG deploy: provider: releases From 5e728ae893b9d7499ed522ac113b7f8d77a4d360 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 20 Nov 2019 18:28:58 -0800 Subject: [PATCH 218/342] Update install.sh --- install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/install.sh b/install.sh index a4fc2b841e6..0420aad329f 100755 --- a/install.sh +++ b/install.sh @@ -211,6 +211,7 @@ initArch() { case $ARCH in amd64) ARCH="amd64";; x86_64) ARCH="amd64";; + aarch64) ARCH="arm64";; # i386) ARCH="386";; *) printf "$red> The system architecture (${ARCH}) is not supported by this installation script.$reset\n"; exit 1;; esac From a9e446b5cdb2e2ffc1c54b385b7eee5d41b53dd3 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 21 Nov 2019 10:51:04 +0100 Subject: [PATCH 219/342] fix(runtime-core) Fix a panic when generating globals. Fix https://github.com/wasmerio/wasmer/issues/979. When we try to get a global that doesn't exist, a panic is generated. This patch just skip that path, and let a proper error be generated later. With this patch, we get: ```sh $ cargo run -- run panic_index_oob_all_backends.wasm Error: ExportNotFound { name: "main" } ``` which is kind of the expected behavior in such situation. --- lib/runtime-core/src/backing.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/runtime-core/src/backing.rs b/lib/runtime-core/src/backing.rs index c88cb953dfb..c3118cfb00f 100644 --- a/lib/runtime-core/src/backing.rs +++ b/lib/runtime-core/src/backing.rs @@ -450,6 +450,11 @@ impl LocalBacking { let value = match &global_init.init { Initializer::Const(value) => value.clone(), Initializer::GetGlobal(import_global_index) => { + // Skip if the global hasn't been initialized properly. + if imports.globals.len() <= import_global_index.index() { + continue; + } + imports.globals[*import_global_index].get() } }; From b1f58bded0925343bd322f5ab60e4b1515f12cea Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 21 Nov 2019 10:57:52 +0100 Subject: [PATCH 220/342] fix(runtime-core) Improve error message when globals are corrupted. Before this patch: ``` $ cargo run -- run panic_index_oob_all_backends.wasm Error: ExportNotFound { name: "main" } ``` With this patch: ```sh $ cargo run -- run panic_index_oob_all_backends.wasm Error: Can't instantiate module: LinkError([Generic { message: "Trying to read the `0` global that isn\'t properly initialized." }]) ``` --- lib/runtime-core/src/backing.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/runtime-core/src/backing.rs b/lib/runtime-core/src/backing.rs index c3118cfb00f..1b50abaf6ab 100644 --- a/lib/runtime-core/src/backing.rs +++ b/lib/runtime-core/src/backing.rs @@ -77,7 +77,7 @@ impl LocalBacking { } }; let mut tables = Self::generate_tables(module); - let mut globals = Self::generate_globals(module, imports); + let mut globals = Self::generate_globals(module, imports)?; // Ensure all initializers are valid before running finalizers Self::validate_memories(module, imports)?; @@ -443,16 +443,20 @@ impl LocalBacking { fn generate_globals( module: &ModuleInner, imports: &ImportBacking, - ) -> BoxedMap { + ) -> LinkResult> { let mut globals = Map::with_capacity(module.info.globals.len()); for (_, global_init) in module.info.globals.iter() { let value = match &global_init.init { Initializer::Const(value) => value.clone(), Initializer::GetGlobal(import_global_index) => { - // Skip if the global hasn't been initialized properly. if imports.globals.len() <= import_global_index.index() { - continue; + return Err(vec![LinkError::Generic { + message: format!( + "Trying to read the `{:?}` global that is not properly initialized.", + import_global_index.index() + ), + }]); } imports.globals[*import_global_index].get() @@ -468,7 +472,7 @@ impl LocalBacking { globals.push(global); } - globals.into_boxed_map() + Ok(globals.into_boxed_map()) } fn finalize_globals( From 7313672d96c6b5fb5bfd97cdd2f69246ca63d359 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 21 Nov 2019 11:03:53 +0100 Subject: [PATCH 221/342] doc(changelog) Add #995. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7b0088dc52..2696d054670 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## **[Unreleased]** +- [#995](https://github.com/wasmerio/wasmer/pull/995) Detect when a global is read without being initialized (emit a proper error instead of panicking) - [#992](https://github.com/wasmerio/wasmer/pull/992) Updates WAPM version to 0.4.1, fix arguments issue introduced in #990 - [#990](https://github.com/wasmerio/wasmer/pull/990) Default wasmer CLI to `run`. Wasmer will now attempt to parse unrecognized command line options as if they were applied to the run command: `wasmer mywasm.wasm --dir=.` now works! - [#987](https://github.com/wasmerio/wasmer/pull/987) Fix `runtime-c-api` header files when compiled by gnuc. From 5f26fcd633d38f3789c737aacf8d65f4e31286e6 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 21 Nov 2019 23:31:10 +0800 Subject: [PATCH 222/342] Make cranelift optional and enable singlepass by default on aarch64. --- Cargo.toml | 4 ++-- Dockerfile | 2 +- Makefile | 8 ++++---- src/bin/wasmer.rs | 15 ++++++++++++++- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8724d91d4a3..c403813b1be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ byteorder = "1.3" errno = "0.2" structopt = "0.3" wabt = "0.9.1" -wasmer-clif-backend = { path = "lib/clif-backend" } +wasmer-clif-backend = { path = "lib/clif-backend", optional = true } wasmer-singlepass-backend = { path = "lib/singlepass-backend", optional = true } wasmer-middleware-common = { path = "lib/middleware-common" } wasmer-runtime = { path = "lib/runtime" } @@ -73,7 +73,7 @@ serde = { version = "1", features = ["derive"] } # used by the plugin example typetag = "0.1" # used by the plugin example [features] -default = ["fast-tests", "wasi", "backend-cranelift"] +default = ["fast-tests", "wasi"] "loader-kernel" = ["wasmer-kernel-loader"] debug = ["wasmer-runtime-core/debug"] trace = ["wasmer-runtime-core/trace"] diff --git a/Dockerfile b/Dockerfile index 6affe470faf..73507be300e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,7 +17,7 @@ FROM wasmer-build-env AS wasmer-build WORKDIR /home/circleci/wasmer COPY . /home/circleci/wasmer RUN sudo chmod -R 777 . -RUN cargo build --release +RUN cargo build --release --features backend-cranelift FROM debian:stretch AS wasmer WORKDIR /root/ diff --git a/Makefile b/Makefile index a19cc70a1e7..eae5028fc8a 100644 --- a/Makefile +++ b/Makefile @@ -102,7 +102,7 @@ llvm: spectests-llvm emtests-llvm wasitests-llvm # All tests capi: - cargo build --release + cargo build --release --features backend-cranelift cargo build -p wasmer-runtime-c-api --release test-capi: capi @@ -151,7 +151,7 @@ lint: precommit: lint test debug: - cargo build --release --features backend-singlepass,debug,trace + cargo build --release --features backend-cranelift,backend-singlepass,debug,trace install: cargo install --path . @@ -220,13 +220,13 @@ check: check-bench # Release release: - cargo build --release --features backend-singlepass,backend-llvm,loader-kernel + cargo build --release --features backend-cranelift,backend-singlepass,backend-llvm,loader-kernel # Only one backend (cranelift) release-clif: # If you are on macOS, you will need mingw-w64 for cross compiling to Windows # brew install mingw-w64 - cargo build --release + cargo build --release --features backend-cranelift release-singlepass: cargo build --release --features backend-singlepass diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 9bdf940a130..e97b9714ebe 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -21,6 +21,7 @@ use std::collections::HashMap; use structopt::{clap, StructOpt}; use wasmer::*; +#[cfg(feature = "backend-cranelift")] use wasmer_clif_backend::CraneliftCompiler; #[cfg(feature = "backend-llvm")] use wasmer_llvm_backend::{LLVMCompiler, LLVMOptions}; @@ -144,7 +145,8 @@ struct Run { #[structopt(parse(from_os_str))] path: PathBuf, - // Disable the cache + /// Name of the backend to use. (x86_64) + #[cfg(target_arch = "x86_64")] #[structopt( long = "backend", default_value = "cranelift", @@ -153,6 +155,16 @@ struct Run { )] backend: Backend, + /// Name of the backend to use. (aarch64) + #[cfg(target_arch = "aarch64")] + #[structopt( + long = "backend", + default_value = "singlepass", + case_insensitive = true, + possible_values = Backend::variants(), + )] + backend: Backend, + /// Invoke a specified function #[structopt(long = "invoke", short = "i")] invoke: Option, @@ -893,6 +905,7 @@ fn get_compiler_by_backend(backend: Backend, _opts: &Run) -> Option return None, + #[cfg(feature = "backend-cranelift")] Backend::Cranelift => Box::new(CraneliftCompiler::new()), #[cfg(feature = "backend-llvm")] Backend::LLVM => Box::new(LLVMCompiler::new()), From 73cc86de0c238a3628cac2aac211f8f0061aca18 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 21 Nov 2019 23:37:17 +0800 Subject: [PATCH 223/342] Fix compilation errors with cranelift. --- Cargo.toml | 1 + src/bin/wasmer.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index c403813b1be..dcce0870460 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,6 +81,7 @@ extra-debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"] # This feature will allow cargo test to run much faster fast-tests = [] backend-cranelift = [ + "wasmer-clif-backend", "wasmer-runtime-core/backend-cranelift", "wasmer-runtime/cranelift", "wasmer-middleware-common-tests/clif", diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index e97b9714ebe..f53d284700d 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -907,6 +907,8 @@ fn get_compiler_by_backend(backend: Backend, _opts: &Run) -> Option return None, #[cfg(feature = "backend-cranelift")] Backend::Cranelift => Box::new(CraneliftCompiler::new()), + #[cfg(not(feature = "backend-cranelift"))] + Backend::Cranelift => return None, #[cfg(feature = "backend-llvm")] Backend::LLVM => Box::new(LLVMCompiler::new()), #[cfg(not(feature = "backend-llvm"))] From d1352554e364724783c2e00616f4fe994228a21e Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 21 Nov 2019 23:37:33 +0800 Subject: [PATCH 224/342] Remove accidentally added test files. --- examples/popcnt.wat | 5 ----- examples/xxx.wat | 39 --------------------------------------- 2 files changed, 44 deletions(-) delete mode 100644 examples/popcnt.wat delete mode 100644 examples/xxx.wat diff --git a/examples/popcnt.wat b/examples/popcnt.wat deleted file mode 100644 index 25ff2ddb086..00000000000 --- a/examples/popcnt.wat +++ /dev/null @@ -1,5 +0,0 @@ -(module - (func $main (export "main") (result i32) - (i32.popcnt (i32.const -1)) - ) -) \ No newline at end of file diff --git a/examples/xxx.wat b/examples/xxx.wat deleted file mode 100644 index 705f5f00c80..00000000000 --- a/examples/xxx.wat +++ /dev/null @@ -1,39 +0,0 @@ -(module - (func $dot_product_example - (param $x0 f64) (param $x1 f64) (param $x2 f64) (param $x3 f64) - (param $y0 f64) (param $y1 f64) (param $y2 f64) (param $y3 f64) - (result f64) - (f64.add (f64.add (f64.add - (f64.mul (local.get $x0) (local.get $y0)) - (f64.mul (local.get $x1) (local.get $y1))) - (f64.mul (local.get $x2) (local.get $y2))) - (f64.mul (local.get $x3) (local.get $y3))) - ) - (func $main (export "main") - (param i32) (param i32) (param i32) (param i32) - (param i32) (param i32) (param i32) (param i32) - (result i32) - (i32.add - (get_local 0) - (i32.add - (get_local 1) - (i32.add - (get_local 2) - (i32.add - (get_local 3) - (i32.add - (get_local 4) - (i32.add - (get_local 5) - (i32.add - (get_local 6) - (get_local 7) - ) - ) - ) - ) - ) - ) - ) - ) -) \ No newline at end of file From 15e3a038ea55a694c3f06cf37b1b92f3131d5e4c Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 22 Nov 2019 00:36:34 +0800 Subject: [PATCH 225/342] Try fixing compilation on Windows. --- lib/runtime-core/src/codegen.rs | 4 +++- lib/runtime-core/src/state.rs | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index 7e8aedd48d5..8cf1b6040c0 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -1,11 +1,12 @@ //! The codegen module provides common functions and data structures used by multiple backends //! during the code generation process. +#[cfg(unix)] +use crate::fault::FaultInfo; use crate::{ backend::RunnableModule, backend::{Backend, CacheGen, Compiler, CompilerConfig, Features, Token}, cache::{Artifact, Error as CacheError}, error::{CompileError, CompileResult}, - fault::FaultInfo, module::{ModuleInfo, ModuleInner}, structures::Map, types::{FuncIndex, FuncSig, SigIndex}, @@ -67,6 +68,7 @@ impl fmt::Debug for InternalEvent { /// Information for a breakpoint pub struct BreakpointInfo<'a> { /// Fault. + #[cfg(unix)] pub fault: Option<&'a FaultInfo>, } diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index e3ab9ca0fc4..1b7d3f34bbe 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -477,6 +477,7 @@ impl InstanceImage { } /// Declarations for x86-64 registers. +#[cfg(unix)] pub mod x64_decl { use super::*; @@ -608,6 +609,7 @@ pub mod x64_decl { } } +#[cfg(unix)] pub mod x64 { //! The x64 state module contains functions to generate state and code for x64 targets. pub use super::x64_decl::*; From 6f3e6fab3b8e7d89e2395ecb340153da1446ea7b Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 22 Nov 2019 00:51:20 +0800 Subject: [PATCH 226/342] Try fixing compilation on Windows. --- lib/runtime-core/src/codegen.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index 8cf1b6040c0..000f1363903 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -66,12 +66,16 @@ impl fmt::Debug for InternalEvent { } /// Information for a breakpoint +#[cfg(unix)] pub struct BreakpointInfo<'a> { /// Fault. - #[cfg(unix)] pub fault: Option<&'a FaultInfo>, } +/// Information for a breakpoint +#[cfg(not(unix))] +pub struct BreakpointInfo {} + /// A trait that represents the functions needed to be implemented to generate code for a module. pub trait ModuleCodeGenerator, RM: RunnableModule, E: Debug> { /// Creates a new module code generator. From 4ec4fcf28a0ea38bc801196137ada5fd0b9c8850 Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 22 Nov 2019 01:46:02 +0800 Subject: [PATCH 227/342] Try fixing middleware failure. --- lib/runtime-core/src/fault.rs | 74 ++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index 776acb4bdfe..d992282d9f9 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -284,48 +284,50 @@ extern "C" fn signal_trap_handler( unsafe { let fault = get_fault_info(siginfo as _, ucontext); - let early_return = CURRENT_CODE_VERSIONS.with(|versions| { - let versions = versions.borrow(); - for v in versions.iter() { - let magic_size = if let Some(x) = get_inline_breakpoint_size(ARCH, v.backend) { - x - } else { - continue; - }; - let ip = fault.ip.get(); - let end = v.base + v.msm.total_size; - if ip >= v.base && ip < end && ip + magic_size <= end { - if let Some(ib) = read_inline_breakpoint( - ARCH, - v.backend, - std::slice::from_raw_parts(ip as *const u8, magic_size), - ) { - match ib.ty { - InlineBreakpointType::Trace => {} - InlineBreakpointType::Middleware => { - let out: Option>> = - with_breakpoint_map(|bkpt_map| { - bkpt_map.and_then(|x| x.get(&ip)).map(|x| { - x(BreakpointInfo { - fault: Some(&fault), + let early_return = allocate_and_run(TRAP_STACK_SIZE, || { + CURRENT_CODE_VERSIONS.with(|versions| { + let versions = versions.borrow(); + for v in versions.iter() { + let magic_size = if let Some(x) = get_inline_breakpoint_size(ARCH, v.backend) { + x + } else { + continue; + }; + let ip = fault.ip.get(); + let end = v.base + v.msm.total_size; + if ip >= v.base && ip < end && ip + magic_size <= end { + if let Some(ib) = read_inline_breakpoint( + ARCH, + v.backend, + std::slice::from_raw_parts(ip as *const u8, magic_size), + ) { + match ib.ty { + InlineBreakpointType::Trace => {} + InlineBreakpointType::Middleware => { + let out: Option>> = + with_breakpoint_map(|bkpt_map| { + bkpt_map.and_then(|x| x.get(&ip)).map(|x| { + x(BreakpointInfo { + fault: Some(&fault), + }) }) - }) - }); - if let Some(Ok(())) = out { - } else { - println!("Failed calling middleware: {:?}", out); + }); + if let Some(Ok(())) = out { + } else { + println!("Failed calling middleware: {:?}", out); + } } + _ => println!("Unknown breakpoint type: {:?}", ib.ty), } - _ => println!("Unknown breakpoint type: {:?}", ib.ty), - } - fault.ip.set(ip + magic_size); - return true; + fault.ip.set(ip + magic_size); + return true; + } + break; } - break; } - } - false + false + }) }); if early_return { return; From 8709708de7385da0872920a24ead9ed09ef5e442 Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 22 Nov 2019 01:57:04 +0800 Subject: [PATCH 228/342] Unwind if breakpoint handler returns error. --- lib/runtime-core/src/fault.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index d992282d9f9..bc64c15fa52 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -282,6 +282,9 @@ extern "C" fn signal_trap_handler( #[cfg(target_arch = "aarch64")] static ARCH: Architecture = Architecture::Aarch64; + let mut should_unwind = false; + let mut unwind_result: Box = Box::new(()); + unsafe { let fault = get_fault_info(siginfo as _, ucontext); let early_return = allocate_and_run(TRAP_STACK_SIZE, || { @@ -313,8 +316,9 @@ extern "C" fn signal_trap_handler( }) }); if let Some(Ok(())) = out { - } else { - println!("Failed calling middleware: {:?}", out); + } else if let Some(Err(e)) = out { + should_unwind = true; + unwind_result = e; } } _ => println!("Unknown breakpoint type: {:?}", ib.ty), @@ -329,13 +333,14 @@ extern "C" fn signal_trap_handler( false }) }); + if should_unwind { + begin_unsafe_unwind(unwind_result); + } if early_return { return; } - let mut unwind_result: Box = Box::new(()); - - let should_unwind = allocate_and_run(TRAP_STACK_SIZE, || { + should_unwind = allocate_and_run(TRAP_STACK_SIZE, || { let mut is_suspend_signal = false; WAS_SIGINT_TRIGGERED.with(|x| x.set(false)); From 4dd810bbac690c972f723a221b821b4a1fbf3353 Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 22 Nov 2019 02:23:51 +0800 Subject: [PATCH 229/342] Ensure code version metadata is pushed properly. --- lib/middleware-common-tests/src/lib.rs | 56 +++++++++++++++++++++----- src/bin/wasmer.rs | 27 ++++++++----- 2 files changed, 63 insertions(+), 20 deletions(-) diff --git a/lib/middleware-common-tests/src/lib.rs b/lib/middleware-common-tests/src/lib.rs index 0b6754c5f65..1515f5cd2a6 100644 --- a/lib/middleware-common-tests/src/lib.rs +++ b/lib/middleware-common-tests/src/lib.rs @@ -4,38 +4,43 @@ mod tests { use wasmer_middleware_common::metering::*; use wasmer_runtime_core::codegen::{MiddlewareChain, StreamingCompiler}; - use wasmer_runtime_core::{backend::Compiler, compile_with, imports, Func}; + use wasmer_runtime_core::fault::{pop_code_version, push_code_version}; + use wasmer_runtime_core::state::CodeVersion; + use wasmer_runtime_core::{ + backend::{Backend, Compiler}, + compile_with, imports, Func, + }; #[cfg(feature = "llvm")] - fn get_compiler(limit: u64) -> impl Compiler { + fn get_compiler(limit: u64) -> (impl Compiler, Backend) { use wasmer_llvm_backend::ModuleCodeGenerator as LLVMMCG; let c: StreamingCompiler = StreamingCompiler::new(move || { let mut chain = MiddlewareChain::new(); chain.push(Metering::new(limit)); chain }); - c + (c, Backend::LLVM) } #[cfg(feature = "singlepass")] - fn get_compiler(limit: u64) -> impl Compiler { + fn get_compiler(limit: u64) -> (impl Compiler, Backend) { use wasmer_singlepass_backend::ModuleCodeGenerator as SinglePassMCG; let c: StreamingCompiler = StreamingCompiler::new(move || { let mut chain = MiddlewareChain::new(); chain.push(Metering::new(limit)); chain }); - c + (c, Backend::Singlepass) } #[cfg(not(any(feature = "llvm", feature = "clif", feature = "singlepass")))] compile_error!("compiler not specified, activate a compiler via features"); #[cfg(feature = "clif")] - fn get_compiler(_limit: u64) -> impl Compiler { + fn get_compiler(_limit: u64) -> (impl Compiler, Backend) { compile_error!("cranelift does not implement metering"); use wasmer_clif_backend::CraneliftCompiler; - CraneliftCompiler::new() + (CraneliftCompiler::new(), Backend::Cranelift) } // Assemblyscript @@ -103,7 +108,8 @@ mod tests { let limit = 100u64; - let module = compile_with(&wasm_binary, &get_compiler(limit)).unwrap(); + let (compiler, backend_id) = get_compiler(limit); + let module = compile_with(&wasm_binary, &compiler).unwrap(); let import_object = imports! {}; let mut instance = module.instantiate(&import_object).unwrap(); @@ -111,7 +117,23 @@ mod tests { set_points_used(&mut instance, 0u64); let add_to: Func<(i32, i32), i32> = instance.func("add_to").unwrap(); + + let cv_pushed = if let Some(msm) = instance.module.runnable_module.get_module_state_map() { + push_code_version(CodeVersion { + baseline: true, + msm: msm, + base: instance.module.runnable_module.get_code().unwrap().as_ptr() as usize, + backend: backend_id, + }); + true + } else { + false + }; + let value = add_to.call(3, 4).unwrap(); + if cv_pushed { + pop_code_version().unwrap(); + } // verify it returns the correct value assert_eq!(value, 7); @@ -127,7 +149,8 @@ mod tests { let limit = 100u64; - let module = compile_with(&wasm_binary, &get_compiler(limit)).unwrap(); + let (compiler, backend_id) = get_compiler(limit); + let module = compile_with(&wasm_binary, &compiler).unwrap(); let import_object = imports! {}; let mut instance = module.instantiate(&import_object).unwrap(); @@ -135,7 +158,22 @@ mod tests { set_points_used(&mut instance, 0u64); let add_to: Func<(i32, i32), i32> = instance.func("add_to").unwrap(); + + let cv_pushed = if let Some(msm) = instance.module.runnable_module.get_module_state_map() { + push_code_version(CodeVersion { + baseline: true, + msm: msm, + base: instance.module.runnable_module.get_code().unwrap().as_ptr() as usize, + backend: backend_id, + }); + true + } else { + false + }; let result = add_to.call(10_000_000, 4); + if cv_pushed { + pop_code_version().unwrap(); + } let err = result.unwrap_err(); match err { diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index f53d284700d..b55f1088481 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -692,18 +692,23 @@ fn execute_wasm(options: &Run) -> Result<(), String> { state::CodeVersion, }; - push_code_version(CodeVersion { - baseline: true, - msm: instance - .module - .runnable_module - .get_module_state_map() - .unwrap(), - base: instance.module.runnable_module.get_code().unwrap().as_ptr() as usize, - backend: options.backend, - }); + let cv_pushed = if let Some(msm) = + instance.module.runnable_module.get_module_state_map() + { + push_code_version(CodeVersion { + baseline: true, + msm: msm, + base: instance.module.runnable_module.get_code().unwrap().as_ptr() as usize, + backend: options.backend, + }); + true + } else { + false + }; let result = start.call(); - pop_code_version().unwrap(); + if cv_pushed { + pop_code_version().unwrap(); + } if let Err(ref err) = result { match err { From 76269572034b2dc7c32a3fa5e8d270b74c1dc2a2 Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 22 Nov 2019 02:38:47 +0800 Subject: [PATCH 230/342] Enable block_trace middleware only on unix. --- lib/middleware-common/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/middleware-common/src/lib.rs b/lib/middleware-common/src/lib.rs index ca0523f95e2..85885383f1d 100644 --- a/lib/middleware-common/src/lib.rs +++ b/lib/middleware-common/src/lib.rs @@ -10,6 +10,7 @@ #![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")] #![doc(html_logo_url = "https://avatars3.githubusercontent.com/u/44205449?s=200&v=4")] +#[cfg(unix)] pub mod block_trace; pub mod call_trace; pub mod metering; From be217e8f8e989ea65ffaf5a57fd96f53dfc9bae9 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 21 Nov 2019 10:57:04 -0800 Subject: [PATCH 231/342] Update from feedback, fix CI issues, update wasi-test --- Cargo.toml | 2 +- lib/wasi-tests/src/lib.rs | 11 +- lib/wasi/Cargo.toml | 7 +- lib/wasi/src/lib.rs | 19 ++- lib/wasi/src/syscalls/legacy/mod.rs | 1 - lib/wasi/src/syscalls/mod.rs | 1 - src/bin/wasmer.rs | 233 ++++++++++++++-------------- 7 files changed, 143 insertions(+), 131 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3d0c6b7addd..41c17719d8a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,8 +58,8 @@ members = [ "lib/wasi-tests", "lib/emscripten-tests", "lib/middleware-common-tests", - "examples/plugin-for-example", "examples/parallel", + "examples/plugin-for-example", "examples/parallel-guest", ] diff --git a/lib/wasi-tests/src/lib.rs b/lib/wasi-tests/src/lib.rs index 4508e432e02..dba6298a7e5 100644 --- a/lib/wasi-tests/src/lib.rs +++ b/lib/wasi-tests/src/lib.rs @@ -16,7 +16,13 @@ fn serializing_works() { b"GOROOT=$HOME/.cargo/bin".into_iter().cloned().collect(), ]; let wasm_binary = include_bytes!("../wasitests/fd_read.wasm"); - let import_object = generate_import_object( + let module = compile(&wasm_binary[..]) + .map_err(|e| format!("Can't compile module: {:?}", e)) + .unwrap(); + + let wasi_version = get_wasi_version(&module).expect("WASI module"); + let import_object = generate_import_object_for_version( + wasi_version, args.clone(), envs.clone(), vec![], @@ -25,9 +31,6 @@ fn serializing_works() { std::path::PathBuf::from("wasitests/test_fs/hamlet"), )], ); - let module = compile(&wasm_binary[..]) - .map_err(|e| format!("Can't compile module: {:?}", e)) - .unwrap(); let state_bytes = { let instance = module.instantiate(&import_object).unwrap(); diff --git a/lib/wasi/Cargo.toml b/lib/wasi/Cargo.toml index e413c313e69..d81e5e895ee 100644 --- a/lib/wasi/Cargo.toml +++ b/lib/wasi/Cargo.toml @@ -20,9 +20,4 @@ serde = { version = "1", features = ["derive"] } wasmer-runtime-core = { path = "../runtime-core", version = "0.10.1" } [target.'cfg(windows)'.dependencies] -winapi = "0.3" - -[features] -# Enable support for the older snapshot0 WASI modules -snapshot0 = [] -default = ["snapshot0"] \ No newline at end of file +winapi = "0.3" \ No newline at end of file diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index c0bb562de1e..ca439bfdbfe 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -130,9 +130,24 @@ pub fn generate_import_object( } } -#[cfg(feature = "snapshot0")] +/// Creates a Wasi [`ImportObject`] with [`WasiState`] for the given [`WasiVersion`]. +pub fn generate_import_object_for_version( + version: WasiVersion, + args: Vec>, + envs: Vec>, + preopened_files: Vec, + mapped_dirs: Vec<(String, PathBuf)>, +) -> ImportObject { + match version { + WasiVersion::Snapshot0 => { + generate_import_object_snapshot0(args, envs, preopened_files, mapped_dirs) + } + WasiVersion::Snapshot1 => generate_import_object(args, envs, preopened_files, mapped_dirs), + } +} + /// Creates a legacy Wasi [`ImportObject`] with [`WasiState`]. -pub fn generate_import_object_snapshot0( +fn generate_import_object_snapshot0( args: Vec>, envs: Vec>, preopened_files: Vec, diff --git a/lib/wasi/src/syscalls/legacy/mod.rs b/lib/wasi/src/syscalls/legacy/mod.rs index 94e713b2300..62cc08f9ef4 100644 --- a/lib/wasi/src/syscalls/legacy/mod.rs +++ b/lib/wasi/src/syscalls/legacy/mod.rs @@ -2,5 +2,4 @@ //! //! If you are relying on legacy WASI, please upgrade for the best experience. -#[cfg(feature = "snapshot0")] pub mod snapshot0; diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index 3cf8d22b7fa..af6ccab2648 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -5,7 +5,6 @@ pub mod unix; #[cfg(any(target_os = "windows"))] pub mod windows; -#[cfg(any(feature = "snapshot0"))] pub mod legacy; use self::types::*; diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index ff8cc884136..03c66a26fa1 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -26,7 +26,7 @@ use wasmer_clif_backend::CraneliftCompiler; use wasmer_llvm_backend::{LLVMCompiler, LLVMOptions}; use wasmer_runtime::{ cache::{Cache as BaseCache, FileSystemCache, WasmHash}, - Func, Value, VERSION, + Value, VERSION, }; #[cfg(feature = "managed")] use wasmer_runtime_core::tiering::{run_tiering, InteractiveShellContext, ShellExitOperation}; @@ -41,25 +41,6 @@ use wasmer_singlepass_backend::SinglePassCompiler; #[cfg(feature = "wasi")] use wasmer_wasi; -// stub module to make conditional compilation happy -#[cfg(not(feature = "wasi"))] -mod wasmer_wasi { - use wasmer_runtime_core::{import::ImportObject, module::Module}; - - pub fn is_wasi_module(_module: &Module) -> bool { - false - } - - pub fn generate_import_object( - _args: Vec>, - _envs: Vec>, - _preopened_files: Vec, - _mapped_dirs: Vec<(String, std::path::PathBuf)>, - ) -> ImportObject { - unimplemented!() - } -} - #[derive(Debug, StructOpt)] #[structopt(name = "wasmer", about = "Wasm execution runtime.", author)] /// The options for the wasmer Command Line Interface @@ -308,6 +289,7 @@ fn get_mapped_dirs(input: &[String]) -> Result, String> { Ok(md) } +#[cfg(feature = "wasi")] fn get_env_var_args(input: &[String]) -> Result, String> { let mut ev = vec![]; for entry in input.iter() { @@ -323,11 +305,111 @@ fn get_env_var_args(input: &[String]) -> Result, String> { Ok(ev) } +/// Helper function for `execute_wasm` (the `Run` command) +#[cfg(feature = "wasi")] +fn execute_wasi( + wasi_version: wasmer_wasi::WasiVersion, + options: &Run, + env_vars: Vec<(&str, &str)>, + module: wasmer_runtime_core::Module, + mapped_dirs: Vec<(String, PathBuf)>, +) -> Result<(), String> { + let args = if let Some(cn) = &options.command_name { + [cn.clone()] + } else { + [options.path.to_str().unwrap().to_owned()] + } + .iter() + .chain(options.args.iter()) + .cloned() + .map(|arg| arg.into_bytes()) + .collect(); + let envs = env_vars + .into_iter() + .map(|(k, v)| format!("{}={}", k, v).into_bytes()) + .collect(); + let preopened_files = options.pre_opened_directories.clone(); + + let import_object = wasmer_wasi::generate_import_object_for_version( + wasi_version, + args, + envs, + preopened_files, + mapped_dirs, + ); + + #[allow(unused_mut)] // mut used in feature + let mut instance = module + .instantiate(&import_object) + .map_err(|e| format!("Can't instantiate WASI module: {:?}", e))?; + + let start: wasmer_runtime::Func<(), ()> = + instance.func("_start").map_err(|e| format!("{:?}", e))?; + + #[cfg(feature = "managed")] + { + let start_raw: extern "C" fn(&mut wasmer_runtime_core::vm::Ctx) = + unsafe { ::std::mem::transmute(start.get_vm_func()) }; + + unsafe { + run_tiering( + module.info(), + &wasm_binary, + if let Some(ref path) = options.resume { + let mut f = File::open(path).unwrap(); + let mut out: Vec = vec![]; + f.read_to_end(&mut out).unwrap(); + Some( + wasmer_runtime_core::state::InstanceImage::from_bytes(&out) + .expect("failed to decode image"), + ) + } else { + None + }, + &import_object, + start_raw, + &mut instance, + options + .optimized_backends + .iter() + .map(|&backend| -> Box Box + Send> { + Box::new(move || get_compiler_by_backend(backend).unwrap()) + }) + .collect(), + interactive_shell, + )? + }; + } + + #[cfg(not(feature = "managed"))] + { + use wasmer_runtime::error::RuntimeError; + let result = start.call(); + + if let Err(ref err) = result { + match err { + RuntimeError::Trap { msg } => return Err(format!("wasm trap occured: {}", msg)), + #[cfg(feature = "wasi")] + RuntimeError::Error { data } => { + if let Some(error_code) = data.downcast_ref::() { + std::process::exit(error_code.code as i32) + } + } + #[cfg(not(feature = "wasi"))] + RuntimeError::Error { .. } => (), + } + return Err(format!("error: {:?}", err)); + } + } + Ok(()) +} + /// Execute a wasm/wat file fn execute_wasm(options: &Run) -> Result<(), String> { let disable_cache = options.disable_cache; let mapped_dirs = get_mapped_dirs(&options.mapped_dirs[..])?; + #[cfg(feature = "wasi")] let env_vars = get_env_var_args(&options.env_vars[..])?; let wasm_path = &options.path; @@ -582,103 +664,22 @@ fn execute_wasm(options: &Run) -> Result<(), String> { ) .map_err(|e| format!("{:?}", e))?; } else { + #[cfg(feature = "wasi")] let wasi_version = wasmer_wasi::get_wasi_version(&module); - if cfg!(feature = "wasi") && wasi_version.is_some() { - let wasi_version = wasi_version.unwrap(); - let args = if let Some(cn) = &options.command_name { - [cn.clone()] - } else { - [options.path.to_str().unwrap().to_owned()] - } - .iter() - .chain(options.args.iter()) - .cloned() - .map(|arg| arg.into_bytes()) - .collect(); - let envs = env_vars - .into_iter() - .map(|(k, v)| format!("{}={}", k, v).into_bytes()) - .collect(); - let preopened_files = options.pre_opened_directories.clone(); - - let import_object = match wasi_version { - wasmer_wasi::WasiVersion::Snapshot0 => { - wasmer_wasi::generate_import_object_snapshot0( - args, - envs, - preopened_files, - mapped_dirs, - ) - } - wasmer_wasi::WasiVersion::Snapshot1 => { - wasmer_wasi::generate_import_object(args, envs, preopened_files, mapped_dirs) - } - }; - - #[allow(unused_mut)] // mut used in feature - let mut instance = module - .instantiate(&import_object) - .map_err(|e| format!("Can't instantiate WASI module: {:?}", e))?; - - let start: Func<(), ()> = instance.func("_start").map_err(|e| format!("{:?}", e))?; - - #[cfg(feature = "managed")] - { - let start_raw: extern "C" fn(&mut wasmer_runtime_core::vm::Ctx) = - unsafe { ::std::mem::transmute(start.get_vm_func()) }; - - unsafe { - run_tiering( - module.info(), - &wasm_binary, - if let Some(ref path) = options.resume { - let mut f = File::open(path).unwrap(); - let mut out: Vec = vec![]; - f.read_to_end(&mut out).unwrap(); - Some( - wasmer_runtime_core::state::InstanceImage::from_bytes(&out) - .expect("failed to decode image"), - ) - } else { - None - }, - &import_object, - start_raw, - &mut instance, - options - .optimized_backends - .iter() - .map(|&backend| -> Box Box + Send> { - Box::new(move || get_compiler_by_backend(backend).unwrap()) - }) - .collect(), - interactive_shell, - )? - }; - } - - #[cfg(not(feature = "managed"))] - { - use wasmer_runtime::error::RuntimeError; - let result = start.call(); - - if let Err(ref err) = result { - match err { - RuntimeError::Trap { msg } => { - return Err(format!("wasm trap occured: {}", msg)) - } - #[cfg(feature = "wasi")] - RuntimeError::Error { data } => { - if let Some(error_code) = data.downcast_ref::() { - std::process::exit(error_code.code as i32) - } - } - #[cfg(not(feature = "wasi"))] - RuntimeError::Error { .. } => (), - } - return Err(format!("error: {:?}", err)); - } - } + #[cfg(feature = "wasi")] + let is_wasi = wasi_version.is_some(); + #[cfg(not(feature = "wasi"))] + let is_wasi = false; + + if is_wasi { + #[cfg(feature = "wasi")] + execute_wasi( + wasi_version.unwrap(), + options, + env_vars, + module, + mapped_dirs, + )?; } else { let import_object = wasmer_runtime_core::import::ImportObject::new(); let instance = module From daee31f8850db2d42b7449aed80c8945309659ea Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 22 Nov 2019 03:30:05 +0800 Subject: [PATCH 232/342] Add changelog entry. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2696d054670..10d37632121 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## **[Unreleased]** +- [#713](https://github.com/wasmerio/wasmer/pull/713) Add AArch64 support for singlepass. - [#995](https://github.com/wasmerio/wasmer/pull/995) Detect when a global is read without being initialized (emit a proper error instead of panicking) - [#992](https://github.com/wasmerio/wasmer/pull/992) Updates WAPM version to 0.4.1, fix arguments issue introduced in #990 - [#990](https://github.com/wasmerio/wasmer/pull/990) Default wasmer CLI to `run`. Wasmer will now attempt to parse unrecognized command line options as if they were applied to the run command: `wasmer mywasm.wasm --dir=.` now works! From ddccdb92b8396e6e7d328ec650cfba7e255ce8aa Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 21 Nov 2019 11:30:44 -0800 Subject: [PATCH 233/342] More fixes for CI --- lib/wasi-tests/tests/wasitests/_common.rs | 10 +++++++++- lib/wasi/src/syscalls/legacy/snapshot0.rs | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/wasi-tests/tests/wasitests/_common.rs b/lib/wasi-tests/tests/wasitests/_common.rs index 958fdf6ad26..304cda58a99 100644 --- a/lib/wasi-tests/tests/wasitests/_common.rs +++ b/lib/wasi-tests/tests/wasitests/_common.rs @@ -33,7 +33,15 @@ macro_rules! assert_wasi_output { let module = wasmer_runtime_core::compile_with(&wasm_bytes[..], &get_compiler()) .expect("WASM can't be compiled"); - let import_object = generate_import_object(vec![], vec![], $po_dir_args, $mapdir_args); + let wasi_version = get_wasi_version(&module).expect("WASI module"); + + let import_object = generate_import_object_for_version( + wasi_version, + vec![], + vec![], + $po_dir_args, + $mapdir_args, + ); let instance = module .instantiate(&import_object) diff --git a/lib/wasi/src/syscalls/legacy/snapshot0.rs b/lib/wasi/src/syscalls/legacy/snapshot0.rs index 38a1811146b..67566a50c7d 100644 --- a/lib/wasi/src/syscalls/legacy/snapshot0.rs +++ b/lib/wasi/src/syscalls/legacy/snapshot0.rs @@ -1,7 +1,7 @@ use crate::ptr::{Array, WasmPtr}; use crate::syscalls; use crate::syscalls::types::{self, snapshot0}; -use wasmer_runtime_core::vm::Ctx; +use wasmer_runtime_core::{debug, vm::Ctx}; /// Wrapper around `syscalls::fd_filestat_get` with extra logic to handle the size /// difference of `wasi_filestat_t` From aeb66ee48e3e32462ed4119dfcbefb115421dd3f Mon Sep 17 00:00:00 2001 From: Syrus Date: Thu, 21 Nov 2019 13:36:44 -0800 Subject: [PATCH 234/342] Simplify compiler test options --- Cargo.lock | 5 +- lib/emscripten-tests/Cargo.toml | 10 +- lib/emscripten-tests/src/lib.rs | 32 +---- lib/emscripten-tests/tests/emtests/_common.rs | 31 +--- lib/runtime/src/lib.rs | 11 +- lib/spectests/Cargo.toml | 10 +- lib/spectests/examples/simple/main.rs | 45 ++---- lib/spectests/examples/test.rs | 31 +--- lib/spectests/tests/semantics.rs | 7 +- lib/spectests/tests/spectest.rs | 135 +++++++----------- lib/wasi-tests/Cargo.toml | 13 +- lib/wasi-tests/src/lib.rs | 3 +- lib/wasi-tests/tests/wasitests/_common.rs | 29 +--- 13 files changed, 105 insertions(+), 257 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 24fa874a31a..37410c3568b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1436,7 +1436,7 @@ dependencies = [ "wasmer-dev-utils 0.10.2", "wasmer-emscripten 0.10.2", "wasmer-llvm-backend 0.10.2", - "wasmer-runtime-core 0.10.2", + "wasmer-runtime 0.10.2", "wasmer-singlepass-backend 0.10.2", ] @@ -1574,7 +1574,7 @@ dependencies = [ "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-clif-backend 0.10.2", "wasmer-llvm-backend 0.10.2", - "wasmer-runtime-core 0.10.2", + "wasmer-runtime 0.10.2", "wasmer-singlepass-backend 0.10.2", ] @@ -1604,7 +1604,6 @@ dependencies = [ "wasmer-dev-utils 0.10.2", "wasmer-llvm-backend 0.10.2", "wasmer-runtime 0.10.2", - "wasmer-runtime-core 0.10.2", "wasmer-singlepass-backend 0.10.2", "wasmer-wasi 0.10.2", ] diff --git a/lib/emscripten-tests/Cargo.toml b/lib/emscripten-tests/Cargo.toml index 49880090faa..6be2a3056eb 100644 --- a/lib/emscripten-tests/Cargo.toml +++ b/lib/emscripten-tests/Cargo.toml @@ -10,8 +10,8 @@ build = "build/mod.rs" [dependencies] wasmer-emscripten = { path = "../emscripten", version = "0.10.2" } -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.10.2" } +wasmer-runtime = { path = "../runtime", version = "0.10.2", default-features = false } +wasmer-clif-backend = { path = "../clif-backend", version = "0.10.2", optional = true} wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.2", optional = true } wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.2", optional = true } @@ -23,6 +23,6 @@ wasmer-dev-utils = { path = "../dev-utils", version = "0.10.2"} glob = "0.3" [features] -clif = [] -llvm = ["wasmer-llvm-backend"] -singlepass = ["wasmer-singlepass-backend"] +clif = ["wasmer-clif-backend", "wasmer-runtime/default-backend-cranelift"] +singlepass = ["wasmer-singlepass-backend", "wasmer-runtime/default-backend-singlepass"] +llvm = ["wasmer-llvm-backend", "wasmer-runtime/default-backend-llvm"] diff --git a/lib/emscripten-tests/src/lib.rs b/lib/emscripten-tests/src/lib.rs index 1da0abc7315..496aa5d73ce 100644 --- a/lib/emscripten-tests/src/lib.rs +++ b/lib/emscripten-tests/src/lib.rs @@ -3,40 +3,14 @@ mod tests { use std::sync::Arc; use wabt::wat2wasm; use wasmer_emscripten::is_emscripten_module; - use wasmer_runtime_core::backend::Compiler; - use wasmer_runtime_core::compile_with; - - #[cfg(feature = "clif")] - fn get_compiler() -> impl Compiler { - use wasmer_clif_backend::CraneliftCompiler; - CraneliftCompiler::new() - } - - #[cfg(feature = "llvm")] - fn get_compiler() -> impl Compiler { - use wasmer_llvm_backend::LLVMCompiler; - LLVMCompiler::new() - } - - #[cfg(feature = "singlepass")] - fn get_compiler() -> impl Compiler { - use wasmer_singlepass_backend::SinglePassCompiler; - SinglePassCompiler::new() - } - - #[cfg(not(any(feature = "llvm", feature = "clif", feature = "singlepass")))] - fn get_compiler() -> impl Compiler { - panic!("compiler not specified, activate a compiler via features"); - use wasmer_clif_backend::CraneliftCompiler; - CraneliftCompiler::new() - } + use wasmer_runtime::compile; #[test] fn should_detect_emscripten_files() { const WAST_BYTES: &[u8] = include_bytes!("tests/is_emscripten_true.wast"); let wasm_binary = wat2wasm(WAST_BYTES.to_vec()).expect("Can't convert to wasm"); let module = - compile_with(&wasm_binary[..], &get_compiler()).expect("WASM can't be compiled"); + compile(&wasm_binary[..]).expect("WASM can't be compiled"); let module = Arc::new(module); assert!(is_emscripten_module(&module)); } @@ -46,7 +20,7 @@ mod tests { const WAST_BYTES: &[u8] = include_bytes!("tests/is_emscripten_false.wast"); let wasm_binary = wat2wasm(WAST_BYTES.to_vec()).expect("Can't convert to wasm"); let module = - compile_with(&wasm_binary[..], &get_compiler()).expect("WASM can't be compiled"); + compile(&wasm_binary[..]).expect("WASM can't be compiled"); let module = Arc::new(module); assert!(!is_emscripten_module(&module)); } diff --git a/lib/emscripten-tests/tests/emtests/_common.rs b/lib/emscripten-tests/tests/emtests/_common.rs index 1e5dfba6e64..2e6c590d907 100644 --- a/lib/emscripten-tests/tests/emtests/_common.rs +++ b/lib/emscripten-tests/tests/emtests/_common.rs @@ -5,39 +5,12 @@ macro_rules! assert_emscripten_output { EmscriptenGlobals, generate_emscripten_env, }; - use wasmer_runtime_core::{ - backend::Compiler, - }; + use wasmer_runtime::compile; use wasmer_dev_utils::stdio::StdioCapturer; - #[cfg(feature = "clif")] - fn get_compiler() -> impl Compiler { - use wasmer_clif_backend::CraneliftCompiler; - CraneliftCompiler::new() - } - - #[cfg(feature = "llvm")] - fn get_compiler() -> impl Compiler { - use wasmer_llvm_backend::LLVMCompiler; - LLVMCompiler::new() - } - - #[cfg(feature = "singlepass")] - fn get_compiler() -> impl Compiler { - use wasmer_singlepass_backend::SinglePassCompiler; - SinglePassCompiler::new() - } - - #[cfg(not(any(feature = "llvm", feature = "clif", feature = "singlepass")))] - fn get_compiler() -> impl Compiler { - panic!("compiler not specified, activate a compiler via features"); - use wasmer_clif_backend::CraneliftCompiler; - CraneliftCompiler::new() - } - let wasm_bytes = include_bytes!($file); - let module = wasmer_runtime_core::compile_with(&wasm_bytes[..], &get_compiler()) + let module = compile(&wasm_bytes[..]) .expect("WASM can't be compiled"); // let module = compile(&wasm_bytes[..]) diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index ad47226fd36..4d3bf4c4f70 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -87,11 +87,11 @@ //! [`wasmer-clif-backend`]: https://crates.io/crates/wasmer-clif-backend //! [`compile_with`]: fn.compile_with.html -pub use wasmer_runtime_core::backend::Backend; +pub use wasmer_runtime_core::backend::{Backend, Features}; pub use wasmer_runtime_core::codegen::{MiddlewareChain, StreamingCompiler}; 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::import::{ImportObject, LikeNamespace}; 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; @@ -131,9 +131,14 @@ pub mod units { pub use wasmer_runtime_core::units::{Bytes, Pages}; } +pub mod types { + //! Various types. + pub use wasmer_runtime_core::types::*; +} + pub mod cache; -use wasmer_runtime_core::backend::{Compiler, CompilerConfig}; +pub use wasmer_runtime_core::backend::{Compiler, CompilerConfig}; /// Compile WebAssembly binary code into a [`Module`]. /// This function is useful if it is necessary to diff --git a/lib/spectests/Cargo.toml b/lib/spectests/Cargo.toml index 54c17ccc1c5..fe02bec5d24 100644 --- a/lib/spectests/Cargo.toml +++ b/lib/spectests/Cargo.toml @@ -9,8 +9,8 @@ edition = "2018" [dependencies] glob = "0.3" -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.10.2" } +wasmer-runtime = { path = "../runtime", version = "0.10.2", default-features = false} +wasmer-clif-backend = { path = "../clif-backend", version = "0.10.2", optional = true} wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.2", optional = true } wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.2", optional = true } @@ -23,6 +23,6 @@ wabt = "0.9.1" [features] default = ["fast-tests"] fast-tests = [] -clif = [] -llvm = ["wasmer-llvm-backend"] -singlepass = ["wasmer-singlepass-backend"] +clif = ["wasmer-clif-backend", "wasmer-runtime/default-backend-cranelift"] +singlepass = ["wasmer-singlepass-backend", "wasmer-runtime/default-backend-singlepass"] +llvm = ["wasmer-llvm-backend", "wasmer-runtime/default-backend-llvm"] diff --git a/lib/spectests/examples/simple/main.rs b/lib/spectests/examples/simple/main.rs index e9309c3c295..20643feb1d4 100644 --- a/lib/spectests/examples/simple/main.rs +++ b/lib/spectests/examples/simple/main.rs @@ -1,46 +1,23 @@ use wabt::wat2wasm; -use wasmer_runtime_core::{ - backend::Compiler, +use wasmer_runtime::{ error, - global::Global, - memory::Memory, - prelude::*, - table::Table, + func, + Global, + Memory, + imports, + compile, + Table, + Ctx, types::{ElementType, MemoryDescriptor, TableDescriptor, Value}, units::Pages, }; -#[cfg(feature = "clif")] -fn get_compiler() -> impl Compiler { - use wasmer_clif_backend::CraneliftCompiler; - CraneliftCompiler::new() -} - -#[cfg(feature = "llvm")] -fn get_compiler() -> impl Compiler { - use wasmer_llvm_backend::LLVMCompiler; - LLVMCompiler::new() -} - -#[cfg(feature = "singlepass")] -fn get_compiler() -> impl Compiler { - use wasmer_singlepass_backend::SinglePassCompiler; - SinglePassCompiler::new() -} - -#[cfg(not(any(feature = "llvm", feature = "clif", feature = "singlepass")))] -fn get_compiler() -> impl Compiler { - panic!("compiler not specified, activate a compiler via features"); - use wasmer_clif_backend::CraneliftCompiler; - CraneliftCompiler::new() -} - static EXAMPLE_WASM: &'static [u8] = include_bytes!("simple.wasm"); fn main() -> error::Result<()> { let wasm_binary = wat2wasm(IMPORT_MODULE.as_bytes()).expect("WAST not valid or malformed"); - let inner_module = wasmer_runtime_core::compile_with(&wasm_binary, &get_compiler())?; + let inner_module = compile(&wasm_binary)?; let memory_desc = MemoryDescriptor::new(Pages(1), Some(Pages(1)), false).unwrap(); let memory = Memory::new(memory_desc).unwrap(); @@ -71,7 +48,7 @@ fn main() -> error::Result<()> { "env" => inner_instance, }; - let outer_module = wasmer_runtime_core::compile_with(EXAMPLE_WASM, &get_compiler())?; + let outer_module = compile(EXAMPLE_WASM)?; let outer_instance = outer_module.instantiate(&outer_imports)?; let ret = outer_instance.call("main", &[Value::I32(42)])?; println!("ret: {:?}", ret); @@ -79,7 +56,7 @@ fn main() -> error::Result<()> { Ok(()) } -fn print_num(ctx: &mut vm::Ctx, n: i32) -> Result { +fn print_num(ctx: &mut Ctx, n: i32) -> Result { println!("print_num({})", n); let memory: &Memory = ctx.memory(0); diff --git a/lib/spectests/examples/test.rs b/lib/spectests/examples/test.rs index 006fc1397d2..77e16abdfea 100644 --- a/lib/spectests/examples/test.rs +++ b/lib/spectests/examples/test.rs @@ -1,5 +1,5 @@ use wabt::wat2wasm; -use wasmer_runtime_core::{backend::Compiler, import::ImportObject, Instance}; +use wasmer_runtime::{ImportObject, Instance, compile}; fn main() { let instance = create_module_1(); @@ -23,38 +23,13 @@ fn create_module_1() -> Instance { (elem (;1;) (i32.const 9) 1)) "#; let wasm_binary = wat2wasm(module_str.as_bytes()).expect("WAST not valid or malformed"); - let module = wasmer_runtime_core::compile_with(&wasm_binary[..], &get_compiler()) + let module = compile(&wasm_binary[..]) .expect("WASM can't be compiled"); module .instantiate(&generate_imports()) .expect("WASM can't be instantiated") } -#[cfg(feature = "clif")] -fn get_compiler() -> impl Compiler { - use wasmer_clif_backend::CraneliftCompiler; - CraneliftCompiler::new() -} - -#[cfg(feature = "llvm")] -fn get_compiler() -> impl Compiler { - use wasmer_llvm_backend::LLVMCompiler; - LLVMCompiler::new() -} - -#[cfg(feature = "singlepass")] -fn get_compiler() -> impl Compiler { - use wasmer_singlepass_backend::SinglePassCompiler; - SinglePassCompiler::new() -} - -#[cfg(not(any(feature = "llvm", feature = "clif", feature = "singlepass")))] -fn get_compiler() -> impl Compiler { - panic!("compiler not specified, activate a compiler via features"); - use wasmer_clif_backend::CraneliftCompiler; - CraneliftCompiler::new() -} - static IMPORT_MODULE: &str = r#" (module (type $t0 (func (param i32))) @@ -68,7 +43,7 @@ static IMPORT_MODULE: &str = r#" pub fn generate_imports() -> ImportObject { let wasm_binary = wat2wasm(IMPORT_MODULE.as_bytes()).expect("WAST not valid or malformed"); - let module = wasmer_runtime_core::compile_with(&wasm_binary[..], &get_compiler()) + let module = compile(&wasm_binary[..]) .expect("WASM can't be compiled"); let instance = module .instantiate(&ImportObject::new()) diff --git a/lib/spectests/tests/semantics.rs b/lib/spectests/tests/semantics.rs index 0bffa9dcaa6..7e1be1f7ac5 100644 --- a/lib/spectests/tests/semantics.rs +++ b/lib/spectests/tests/semantics.rs @@ -1,10 +1,9 @@ #[cfg(test)] mod tests { use wabt::wat2wasm; - use wasmer_clif_backend::CraneliftCompiler; - use wasmer_runtime_core::{ + use wasmer_runtime::{ error::{CallError, RuntimeError}, - import::ImportObject, + ImportObject, }; // The semantics of stack overflow are documented at: @@ -22,7 +21,7 @@ mod tests { (elem (;0;) (i32.const 0) 0)) "#; let wasm_binary = wat2wasm(module_str.as_bytes()).expect("WAST not valid or malformed"); - let module = wasmer_runtime_core::compile_with(&wasm_binary[..], &CraneliftCompiler::new()) + let module = wasmer_runtime::compile(&wasm_binary[..]) .expect("WASM can't be compiled"); let instance = module .instantiate(&ImportObject::new()) diff --git a/lib/spectests/tests/spectest.rs b/lib/spectests/tests/spectest.rs index 9bb6f631c7c..96ab1c31766 100644 --- a/lib/spectests/tests/spectest.rs +++ b/lib/spectests/tests/spectest.rs @@ -63,31 +63,6 @@ mod tests { } } - #[cfg(feature = "clif")] - fn get_compiler() -> impl Compiler { - use wasmer_clif_backend::CraneliftCompiler; - CraneliftCompiler::new() - } - - #[cfg(feature = "llvm")] - fn get_compiler() -> impl Compiler { - use wasmer_llvm_backend::LLVMCompiler; - LLVMCompiler::new() - } - - #[cfg(feature = "singlepass")] - fn get_compiler() -> impl Compiler { - use wasmer_singlepass_backend::SinglePassCompiler; - SinglePassCompiler::new() - } - - #[cfg(not(any(feature = "llvm", feature = "clif", feature = "singlepass")))] - fn get_compiler() -> impl Compiler { - panic!("compiler not specified, activate a compiler via features"); - use wasmer_clif_backend::CraneliftCompiler; - CraneliftCompiler::new() - } - #[cfg(feature = "clif")] fn get_compiler_name() -> &'static str { "clif" @@ -241,20 +216,23 @@ mod tests { use std::panic::AssertUnwindSafe; use std::path::PathBuf; use wabt::script::{Action, Command, CommandKind, ScriptParser, Value}; - use wasmer_runtime_core::backend::{Compiler, CompilerConfig, Features}; - use wasmer_runtime_core::error::CompileError; - use wasmer_runtime_core::import::ImportObject; - use wasmer_runtime_core::Instance; - use wasmer_runtime_core::{ - export::Export, - global::Global, - import::LikeNamespace, - memory::Memory, - table::Table, + use wasmer_runtime::{ + CompilerConfig, + ImportObject, + LikeNamespace, + Instance, + error::{CompileError}, + Export, + Global, + Memory, + Table, types::{ElementType, MemoryDescriptor, TableDescriptor}, units::Pages, + + Features, + func, imports, Ctx, + compile_with_config, }; - use wasmer_runtime_core::{func, imports, vm::Ctx}; fn parse_and_run( path: &PathBuf, @@ -328,9 +306,8 @@ mod tests { }, ..Default::default() }; - let module = wasmer_runtime_core::compile_with_config( + let module = compile_with_config( &module.into_vec(), - &get_compiler(), config, ) .expect("WASM can't be compiled"); @@ -375,7 +352,7 @@ mod tests { &named_modules, &module, |instance| { - let params: Vec = + let params: Vec = args.iter().cloned().map(convert_value).collect(); instance.call(&field, ¶ms[..]) }, @@ -507,7 +484,7 @@ mod tests { } => { let maybe_call_result = with_instance(instance.clone(), &named_modules, &module, |instance| { - let params: Vec = + let params: Vec = args.iter().cloned().map(convert_value).collect(); instance.call(&field, ¶ms[..]) }); @@ -578,7 +555,7 @@ mod tests { } => { let maybe_call_result = with_instance(instance.clone(), &named_modules, &module, |instance| { - let params: Vec = + let params: Vec = args.iter().cloned().map(convert_value).collect(); instance.call(&field, ¶ms[..]) }); @@ -649,7 +626,7 @@ mod tests { } => { let maybe_call_result = with_instance(instance.clone(), &named_modules, &module, |instance| { - let params: Vec = + let params: Vec = args.iter().cloned().map(convert_value).collect(); instance.call(&field, ¶ms[..]) }); @@ -667,7 +644,7 @@ mod tests { ); } else { let call_result = maybe_call_result.unwrap(); - use wasmer_runtime_core::error::{CallError, RuntimeError}; + use wasmer_runtime::error::{CallError, RuntimeError}; match call_result { Err(e) => { match e { @@ -738,9 +715,8 @@ mod tests { }, ..Default::default() }; - wasmer_runtime_core::compile_with_config( + compile_with_config( &module.into_vec(), - &get_compiler(), config, ) }); @@ -794,9 +770,8 @@ mod tests { }, ..Default::default() }; - wasmer_runtime_core::compile_with_config( + compile_with_config( &module.into_vec(), - &get_compiler(), config, ) }); @@ -849,9 +824,8 @@ mod tests { }, ..Default::default() }; - let module = wasmer_runtime_core::compile_with_config( + let module = compile_with_config( &module.into_vec(), - &get_compiler(), config, ) .expect("WASM can't be compiled"); @@ -891,7 +865,7 @@ mod tests { &named_modules, &module, |instance| { - let params: Vec = + let params: Vec = args.iter().cloned().map(convert_value).collect(); instance.call(&field, ¶ms[..]) }, @@ -948,9 +922,8 @@ mod tests { }, ..Default::default() }; - let module = wasmer_runtime_core::compile_with_config( + let module = compile_with_config( &module.into_vec(), - &get_compiler(), config, ) .expect("WASM can't be compiled"); @@ -987,7 +960,7 @@ mod tests { ); } Err(e) => match e { - wasmer_runtime_core::error::Error::LinkError(_) => { + wasmer_runtime::error::Error::LinkError(_) => { test_report.count_passed(); } _ => { @@ -1046,7 +1019,7 @@ mod tests { } => { let maybe_call_result = with_instance(instance.clone(), &named_modules, &module, |instance| { - let params: Vec = + let params: Vec = args.iter().cloned().map(convert_value).collect(); instance.call(&field, ¶ms[..]) }); @@ -1094,29 +1067,29 @@ mod tests { Ok(test_report) } - fn is_canonical_nan(val: wasmer_runtime_core::types::Value) -> bool { + fn is_canonical_nan(val: wasmer_runtime::types::Value) -> bool { match val { - wasmer_runtime_core::types::Value::F32(x) => x.is_canonical_nan(), - wasmer_runtime_core::types::Value::F64(x) => x.is_canonical_nan(), + wasmer_runtime::types::Value::F32(x) => x.is_canonical_nan(), + wasmer_runtime::types::Value::F64(x) => x.is_canonical_nan(), _ => panic!("value is not a float {:?}", val), } } - fn is_arithmetic_nan(val: wasmer_runtime_core::types::Value) -> bool { + fn is_arithmetic_nan(val: wasmer_runtime::types::Value) -> bool { match val { - wasmer_runtime_core::types::Value::F32(x) => x.is_quiet_nan(), - wasmer_runtime_core::types::Value::F64(x) => x.is_quiet_nan(), + wasmer_runtime::types::Value::F32(x) => x.is_quiet_nan(), + wasmer_runtime::types::Value::F64(x) => x.is_quiet_nan(), _ => panic!("value is not a float {:?}", val), } } - fn value_to_hex(val: wasmer_runtime_core::types::Value) -> String { + fn value_to_hex(val: wasmer_runtime::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), + wasmer_runtime::types::Value::I32(x) => format!("{:#x}", x), + wasmer_runtime::types::Value::I64(x) => format!("{:#x}", x), + wasmer_runtime::types::Value::F32(x) => format!("{:#x}", x.to_bits()), + wasmer_runtime::types::Value::F64(x) => format!("{:#x}", x.to_bits()), + wasmer_runtime::types::Value::V128(x) => format!("{:#x}", x), } } @@ -1129,13 +1102,13 @@ mod tests { V128(u128), } - fn convert_wasmer_value(other: wasmer_runtime_core::types::Value) -> SpectestValue { + fn convert_wasmer_value(other: wasmer_runtime::types::Value) -> SpectestValue { match other { - wasmer_runtime_core::types::Value::I32(v) => SpectestValue::I32(v), - wasmer_runtime_core::types::Value::I64(v) => SpectestValue::I64(v), - wasmer_runtime_core::types::Value::F32(v) => SpectestValue::F32(v.to_bits()), - wasmer_runtime_core::types::Value::F64(v) => SpectestValue::F64(v.to_bits()), - wasmer_runtime_core::types::Value::V128(v) => SpectestValue::V128(v), + wasmer_runtime::types::Value::I32(v) => SpectestValue::I32(v), + wasmer_runtime::types::Value::I64(v) => SpectestValue::I64(v), + wasmer_runtime::types::Value::F32(v) => SpectestValue::F32(v.to_bits()), + wasmer_runtime::types::Value::F64(v) => SpectestValue::F64(v.to_bits()), + wasmer_runtime::types::Value::V128(v) => SpectestValue::V128(v), } } @@ -1149,13 +1122,13 @@ mod tests { } } - fn convert_value(other: Value) -> wasmer_runtime_core::types::Value { + fn convert_value(other: Value) -> wasmer_runtime::types::Value { match other { - Value::I32(v) => wasmer_runtime_core::types::Value::I32(v), - Value::I64(v) => wasmer_runtime_core::types::Value::I64(v), - Value::F32(v) => wasmer_runtime_core::types::Value::F32(v), - Value::F64(v) => wasmer_runtime_core::types::Value::F64(v), - Value::V128(v) => wasmer_runtime_core::types::Value::V128(v), + Value::I32(v) => wasmer_runtime::types::Value::I32(v), + Value::I64(v) => wasmer_runtime::types::Value::I64(v), + Value::F32(v) => wasmer_runtime::types::Value::F32(v), + Value::F64(v) => wasmer_runtime::types::Value::F64(v), + Value::V128(v) => wasmer_runtime::types::Value::V128(v), } } @@ -1199,9 +1172,9 @@ mod tests { let memory_desc = MemoryDescriptor::new(Pages(1), Some(Pages(2)), false).unwrap(); let memory = Memory::new(memory_desc).unwrap(); - let global_i32 = Global::new(wasmer_runtime_core::types::Value::I32(666)); - let global_f32 = Global::new(wasmer_runtime_core::types::Value::F32(666.0)); - let global_f64 = Global::new(wasmer_runtime_core::types::Value::F64(666.0)); + let global_i32 = Global::new(wasmer_runtime::types::Value::I32(666)); + let global_f32 = Global::new(wasmer_runtime::types::Value::F32(666.0)); + let global_f64 = Global::new(wasmer_runtime::types::Value::F64(666.0)); let table = Table::new(TableDescriptor { element: ElementType::Anyfunc, diff --git a/lib/wasi-tests/Cargo.toml b/lib/wasi-tests/Cargo.toml index 05544c7a3de..fa81d0fc114 100644 --- a/lib/wasi-tests/Cargo.toml +++ b/lib/wasi-tests/Cargo.toml @@ -9,22 +9,21 @@ publish = false build = "build/mod.rs" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } -wasmer-runtime = { path = "../runtime", version = "0.10.2" } +# We set default features to false to be able to use the singlepass backend properly +wasmer-runtime = { path = "../runtime", version = "0.10.2", default-features = false } wasmer-wasi = { path = "../wasi", version = "0.10.2" } # hack to get tests to work +wasmer-clif-backend = { path = "../clif-backend", version = "0.10.2", optional = true} wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.2", optional = true } wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.2", optional = true } - [build-dependencies] glob = "0.3" [dev-dependencies] -wasmer-clif-backend = { path = "../clif-backend", version = "0.10.2" } wasmer-dev-utils = { path = "../dev-utils", version = "0.10.2"} [features] -clif = [] -singlepass = ["wasmer-singlepass-backend"] -llvm = ["wasmer-llvm-backend"] +clif = ["wasmer-clif-backend", "wasmer-runtime/default-backend-cranelift"] +singlepass = ["wasmer-singlepass-backend", "wasmer-runtime/default-backend-singlepass"] +llvm = ["wasmer-llvm-backend", "wasmer-runtime/default-backend-llvm"] diff --git a/lib/wasi-tests/src/lib.rs b/lib/wasi-tests/src/lib.rs index 4508e432e02..7e3faecf365 100644 --- a/lib/wasi-tests/src/lib.rs +++ b/lib/wasi-tests/src/lib.rs @@ -1,6 +1,5 @@ #![cfg(test)] -use wasmer_runtime::{compile, Func}; -use wasmer_runtime_core::vm::Ctx; +use wasmer_runtime::{compile, Func, Ctx}; use wasmer_wasi::{state::*, *}; use std::ffi::c_void; diff --git a/lib/wasi-tests/tests/wasitests/_common.rs b/lib/wasi-tests/tests/wasitests/_common.rs index 958fdf6ad26..7aedda0c27c 100644 --- a/lib/wasi-tests/tests/wasitests/_common.rs +++ b/lib/wasi-tests/tests/wasitests/_common.rs @@ -1,36 +1,11 @@ macro_rules! assert_wasi_output { ($file:expr, $name:expr, $po_dir_args: expr, $mapdir_args:expr, $envvar_args:expr, $expected:expr) => {{ use wasmer_dev_utils::stdio::StdioCapturer; - use wasmer_runtime_core::{backend::Compiler, Func}; + use wasmer_runtime::Func; use wasmer_wasi::generate_import_object; - - #[cfg(feature = "clif")] - fn get_compiler() -> impl Compiler { - use wasmer_clif_backend::CraneliftCompiler; - CraneliftCompiler::new() - } - - #[cfg(feature = "llvm")] - fn get_compiler() -> impl Compiler { - use wasmer_llvm_backend::LLVMCompiler; - LLVMCompiler::new() - } - - #[cfg(feature = "singlepass")] - fn get_compiler() -> impl Compiler { - use wasmer_singlepass_backend::SinglePassCompiler; - SinglePassCompiler::new() - } - - #[cfg(not(any(feature = "llvm", feature = "clif", feature = "singlepass")))] - fn get_compiler() -> impl Compiler { - compile_error!("compiler not specified, activate a compiler via features"); - unreachable!(); - } - let wasm_bytes = include_bytes!($file); - let module = wasmer_runtime_core::compile_with(&wasm_bytes[..], &get_compiler()) + let module = wasmer_runtime::compile(&wasm_bytes[..]) .expect("WASM can't be compiled"); let import_object = generate_import_object(vec![], vec![], $po_dir_args, $mapdir_args); From c3f93f1275748f84ba4d5ac8c24fc97860765456 Mon Sep 17 00:00:00 2001 From: Syrus Date: Thu, 21 Nov 2019 13:38:22 -0800 Subject: [PATCH 235/342] Fixed formatting --- lib/emscripten-tests/src/lib.rs | 6 +-- lib/spectests/examples/simple/main.rs | 10 +---- lib/spectests/examples/test.rs | 8 ++-- lib/spectests/tests/semantics.rs | 3 +- lib/spectests/tests/spectest.rs | 49 ++++++----------------- lib/wasi-tests/src/lib.rs | 2 +- lib/wasi-tests/tests/wasitests/_common.rs | 3 +- 7 files changed, 23 insertions(+), 58 deletions(-) diff --git a/lib/emscripten-tests/src/lib.rs b/lib/emscripten-tests/src/lib.rs index 496aa5d73ce..59bcf90ebf7 100644 --- a/lib/emscripten-tests/src/lib.rs +++ b/lib/emscripten-tests/src/lib.rs @@ -9,8 +9,7 @@ mod tests { fn should_detect_emscripten_files() { const WAST_BYTES: &[u8] = include_bytes!("tests/is_emscripten_true.wast"); let wasm_binary = wat2wasm(WAST_BYTES.to_vec()).expect("Can't convert to wasm"); - let module = - compile(&wasm_binary[..]).expect("WASM can't be compiled"); + let module = compile(&wasm_binary[..]).expect("WASM can't be compiled"); let module = Arc::new(module); assert!(is_emscripten_module(&module)); } @@ -19,8 +18,7 @@ mod tests { fn should_detect_non_emscripten_files() { const WAST_BYTES: &[u8] = include_bytes!("tests/is_emscripten_false.wast"); let wasm_binary = wat2wasm(WAST_BYTES.to_vec()).expect("Can't convert to wasm"); - let module = - compile(&wasm_binary[..]).expect("WASM can't be compiled"); + let module = compile(&wasm_binary[..]).expect("WASM can't be compiled"); let module = Arc::new(module); assert!(!is_emscripten_module(&module)); } diff --git a/lib/spectests/examples/simple/main.rs b/lib/spectests/examples/simple/main.rs index 20643feb1d4..6ef87047913 100644 --- a/lib/spectests/examples/simple/main.rs +++ b/lib/spectests/examples/simple/main.rs @@ -1,15 +1,9 @@ use wabt::wat2wasm; use wasmer_runtime::{ - error, - func, - Global, - Memory, - imports, - compile, - Table, - Ctx, + compile, error, func, imports, types::{ElementType, MemoryDescriptor, TableDescriptor, Value}, units::Pages, + Ctx, Global, Memory, Table, }; static EXAMPLE_WASM: &'static [u8] = include_bytes!("simple.wasm"); diff --git a/lib/spectests/examples/test.rs b/lib/spectests/examples/test.rs index 77e16abdfea..eff7793b9b6 100644 --- a/lib/spectests/examples/test.rs +++ b/lib/spectests/examples/test.rs @@ -1,5 +1,5 @@ use wabt::wat2wasm; -use wasmer_runtime::{ImportObject, Instance, compile}; +use wasmer_runtime::{compile, ImportObject, Instance}; fn main() { let instance = create_module_1(); @@ -23,8 +23,7 @@ fn create_module_1() -> Instance { (elem (;1;) (i32.const 9) 1)) "#; let wasm_binary = wat2wasm(module_str.as_bytes()).expect("WAST not valid or malformed"); - let module = compile(&wasm_binary[..]) - .expect("WASM can't be compiled"); + let module = compile(&wasm_binary[..]).expect("WASM can't be compiled"); module .instantiate(&generate_imports()) .expect("WASM can't be instantiated") @@ -43,8 +42,7 @@ static IMPORT_MODULE: &str = r#" pub fn generate_imports() -> ImportObject { let wasm_binary = wat2wasm(IMPORT_MODULE.as_bytes()).expect("WAST not valid or malformed"); - let module = compile(&wasm_binary[..]) - .expect("WASM can't be compiled"); + let module = compile(&wasm_binary[..]).expect("WASM can't be compiled"); let instance = module .instantiate(&ImportObject::new()) .expect("WASM can't be instantiated"); diff --git a/lib/spectests/tests/semantics.rs b/lib/spectests/tests/semantics.rs index 7e1be1f7ac5..eadbeef0e78 100644 --- a/lib/spectests/tests/semantics.rs +++ b/lib/spectests/tests/semantics.rs @@ -21,8 +21,7 @@ mod tests { (elem (;0;) (i32.const 0) 0)) "#; let wasm_binary = wat2wasm(module_str.as_bytes()).expect("WAST not valid or malformed"); - let module = wasmer_runtime::compile(&wasm_binary[..]) - .expect("WASM can't be compiled"); + let module = wasmer_runtime::compile(&wasm_binary[..]).expect("WASM can't be compiled"); let instance = module .instantiate(&ImportObject::new()) .expect("WASM can't be instantiated"); diff --git a/lib/spectests/tests/spectest.rs b/lib/spectests/tests/spectest.rs index 96ab1c31766..3b03b598f4b 100644 --- a/lib/spectests/tests/spectest.rs +++ b/lib/spectests/tests/spectest.rs @@ -217,21 +217,13 @@ mod tests { use std::path::PathBuf; use wabt::script::{Action, Command, CommandKind, ScriptParser, Value}; use wasmer_runtime::{ - CompilerConfig, - ImportObject, - LikeNamespace, - Instance, - error::{CompileError}, - Export, - Global, - Memory, - Table, + compile_with_config, + error::CompileError, + func, imports, types::{ElementType, MemoryDescriptor, TableDescriptor}, units::Pages, - - Features, - func, imports, Ctx, - compile_with_config, + CompilerConfig, Ctx, Export, Features, Global, ImportObject, Instance, LikeNamespace, + Memory, Table, }; fn parse_and_run( @@ -306,11 +298,8 @@ mod tests { }, ..Default::default() }; - let module = compile_with_config( - &module.into_vec(), - config, - ) - .expect("WASM can't be compiled"); + let module = compile_with_config(&module.into_vec(), config) + .expect("WASM can't be compiled"); let i = module .instantiate(&spectest_import_object) .expect("WASM can't be instantiated"); @@ -715,10 +704,7 @@ mod tests { }, ..Default::default() }; - compile_with_config( - &module.into_vec(), - config, - ) + compile_with_config(&module.into_vec(), config) }); match result { Ok(module) => { @@ -770,10 +756,7 @@ mod tests { }, ..Default::default() }; - compile_with_config( - &module.into_vec(), - config, - ) + compile_with_config(&module.into_vec(), config) }); match result { @@ -824,11 +807,8 @@ mod tests { }, ..Default::default() }; - let module = compile_with_config( - &module.into_vec(), - config, - ) - .expect("WASM can't be compiled"); + let module = compile_with_config(&module.into_vec(), config) + .expect("WASM can't be compiled"); let result = panic::catch_unwind(AssertUnwindSafe(|| { module .instantiate(&spectest_import_object) @@ -922,11 +902,8 @@ mod tests { }, ..Default::default() }; - let module = compile_with_config( - &module.into_vec(), - config, - ) - .expect("WASM can't be compiled"); + let module = compile_with_config(&module.into_vec(), config) + .expect("WASM can't be compiled"); module.instantiate(&spectest_import_object) })); match result { diff --git a/lib/wasi-tests/src/lib.rs b/lib/wasi-tests/src/lib.rs index 7e3faecf365..a6853b4f584 100644 --- a/lib/wasi-tests/src/lib.rs +++ b/lib/wasi-tests/src/lib.rs @@ -1,5 +1,5 @@ #![cfg(test)] -use wasmer_runtime::{compile, Func, Ctx}; +use wasmer_runtime::{compile, Ctx, Func}; use wasmer_wasi::{state::*, *}; use std::ffi::c_void; diff --git a/lib/wasi-tests/tests/wasitests/_common.rs b/lib/wasi-tests/tests/wasitests/_common.rs index 7aedda0c27c..7b26bd8d5fe 100644 --- a/lib/wasi-tests/tests/wasitests/_common.rs +++ b/lib/wasi-tests/tests/wasitests/_common.rs @@ -5,8 +5,7 @@ macro_rules! assert_wasi_output { use wasmer_wasi::generate_import_object; let wasm_bytes = include_bytes!($file); - let module = wasmer_runtime::compile(&wasm_bytes[..]) - .expect("WASM can't be compiled"); + let module = wasmer_runtime::compile(&wasm_bytes[..]).expect("WASM can't be compiled"); let import_object = generate_import_object(vec![], vec![], $po_dir_args, $mapdir_args); From bdeec521523d66c043140b5559a8e804cdd6a403 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 21 Nov 2019 14:00:46 -0800 Subject: [PATCH 236/342] Fix imports in test; copy manual implementations of `Debug` for wasi --- lib/wasi-tests/tests/wasitests/_common.rs | 2 +- lib/wasi/src/syscalls/types.rs | 48 +++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/lib/wasi-tests/tests/wasitests/_common.rs b/lib/wasi-tests/tests/wasitests/_common.rs index 304cda58a99..82920c0c9f9 100644 --- a/lib/wasi-tests/tests/wasitests/_common.rs +++ b/lib/wasi-tests/tests/wasitests/_common.rs @@ -2,7 +2,7 @@ macro_rules! assert_wasi_output { ($file:expr, $name:expr, $po_dir_args: expr, $mapdir_args:expr, $envvar_args:expr, $expected:expr) => {{ use wasmer_dev_utils::stdio::StdioCapturer; use wasmer_runtime_core::{backend::Compiler, Func}; - use wasmer_wasi::generate_import_object; + use wasmer_wasi::{generate_import_object_for_version, get_wasi_version}; #[cfg(feature = "clif")] fn get_compiler() -> impl Compiler { diff --git a/lib/wasi/src/syscalls/types.rs b/lib/wasi/src/syscalls/types.rs index 6e4444ee933..5f5559ce497 100644 --- a/lib/wasi/src/syscalls/types.rs +++ b/lib/wasi/src/syscalls/types.rs @@ -752,4 +752,52 @@ pub mod snapshot0 { } unsafe impl ValueType for __wasi_filestat_t {} + + impl std::fmt::Debug for __wasi_filestat_t { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let convert_ts_into_time_string = |ts| { + let tspec = + time::Timespec::new(ts as i64 / 1_000_000_000, (ts % 1_000_000_000) as i32); + let tm = time::at(tspec); + let out_time = tm.rfc822(); + format!("{} ({})", out_time, ts) + }; + f.debug_struct("__wasi_filestat_t") + .field("st_dev", &self.st_dev) + .field("st_ino", &self.st_ino) + .field( + "st_filetype", + &format!( + "{} ({})", + super::wasi_filetype_to_name(self.st_filetype), + self.st_filetype, + ), + ) + .field("st_nlink", &self.st_nlink) + .field("st_size", &self.st_size) + .field("st_atim", &convert_ts_into_time_string(self.st_atim)) + .field("st_mtim", &convert_ts_into_time_string(self.st_mtim)) + .field("st_ctim", &convert_ts_into_time_string(self.st_ctim)) + .finish() + } + } + + impl std::fmt::Debug for __wasi_subscription_t { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("__wasi_subscription_t") + .field("userdata", &self.userdata) + .field("type", &super::eventtype_to_str(self.type_)) + .field( + "u", + match self.type_ { + super::__WASI_EVENTTYPE_CLOCK => unsafe { &self.u.clock }, + super::__WASI_EVENTTYPE_FD_READ | super::__WASI_EVENTTYPE_FD_WRITE => unsafe { + &self.u.fd_readwrite + }, + _ => &"INVALID EVENTTYPE", + }, + ) + .finish() + } + } } From 5da44c3bf880da8567eaee201db787e8cb47603b Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 22 Nov 2019 07:26:35 +0800 Subject: [PATCH 237/342] Add 'fault' placeholder for Windows. --- lib/runtime-core/src/codegen.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index 000f1363903..99158fb1501 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -74,7 +74,10 @@ pub struct BreakpointInfo<'a> { /// Information for a breakpoint #[cfg(not(unix))] -pub struct BreakpointInfo {} +pub struct BreakpointInfo { + /// Fault placeholder. + pub fault: Option<()>, +} /// A trait that represents the functions needed to be implemented to generate code for a module. pub trait ModuleCodeGenerator, RM: RunnableModule, E: Debug> { From ee7b0d625a2cdc7df33315d6467039e60c19ce39 Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 22 Nov 2019 08:07:24 +0800 Subject: [PATCH 238/342] Skip push/pop code version on Windows. --- src/bin/wasmer.rs | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index b55f1088481..37212ba33bf 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -687,27 +687,37 @@ fn execute_wasm(options: &Run) -> Result<(), String> { #[cfg(not(feature = "managed"))] { use wasmer_runtime::error::RuntimeError; + #[cfg(unix)] use wasmer_runtime_core::{ fault::{pop_code_version, push_code_version}, state::CodeVersion, }; - let cv_pushed = if let Some(msm) = - instance.module.runnable_module.get_module_state_map() + let result; + + #[cfg(unix)] { - push_code_version(CodeVersion { - baseline: true, - msm: msm, - base: instance.module.runnable_module.get_code().unwrap().as_ptr() as usize, - backend: options.backend, - }); - true - } else { - false - }; - let result = start.call(); - if cv_pushed { - pop_code_version().unwrap(); + let cv_pushed = + if let Some(msm) = instance.module.runnable_module.get_module_state_map() { + push_code_version(CodeVersion { + baseline: true, + msm: msm, + base: instance.module.runnable_module.get_code().unwrap().as_ptr() + as usize, + backend: options.backend, + }); + true + } else { + false + }; + result = start.call(); + if cv_pushed { + pop_code_version().unwrap(); + } + } + #[cfg(not(unix))] + { + result = start.call(); } if let Err(ref err) = result { From 31437a1e749f8c0b2154ccbb3a5365c0ab7cdbab Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 21 Nov 2019 17:22:21 -0800 Subject: [PATCH 239/342] Autodetect default backend, add features for architecture type --- Cargo.lock | 1 + Cargo.toml | 8 +++++- lib/middleware-common-tests/Cargo.toml | 5 ++-- lib/runtime-core-tests/Cargo.toml | 2 +- lib/runtime/Cargo.toml | 2 +- lib/runtime/build.rs | 38 ++++++++++++++++++++++++++ 6 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 lib/runtime/build.rs diff --git a/Cargo.lock b/Cargo.lock index 37410c3568b..9db25328286 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1353,6 +1353,7 @@ dependencies = [ "wasmer-middleware-common-tests 0.10.2", "wasmer-runtime 0.10.2", "wasmer-runtime-core 0.10.2", + "wasmer-runtime-core-tests 0.10.2", "wasmer-singlepass-backend 0.10.2", "wasmer-wasi 0.10.2", "wasmer-wasi-tests 0.10.2", diff --git a/Cargo.toml b/Cargo.toml index 8724d91d4a3..48c4cfce51e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ wasmer-kernel-loader = { path = "lib/kernel-loader", optional = true } wasmer-dev-utils = { path = "lib/dev-utils", optional = true } wasmer-wasi-tests = { path = "lib/wasi-tests", optional = true } wasmer-middleware-common-tests = { path = "lib/middleware-common-tests", optional = true } +wasmer-runtime-core-tests = { path = "lib/runtime-core-tests", optional = true } wasmer-emscripten-tests = { path = "lib/emscripten-tests", optional = true } [workspace] @@ -73,8 +74,10 @@ serde = { version = "1", features = ["derive"] } # used by the plugin example typetag = "0.1" # used by the plugin example [features] -default = ["fast-tests", "wasi", "backend-cranelift"] +default = ["fast-tests", "wasi", "x86_64"] "loader-kernel" = ["wasmer-kernel-loader"] +aarch64 = ["backend-singlepass"] +x86_64 = ["backend-cranelift"] debug = ["wasmer-runtime-core/debug"] trace = ["wasmer-runtime-core/trace"] extra-debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"] @@ -84,6 +87,7 @@ backend-cranelift = [ "wasmer-runtime-core/backend-cranelift", "wasmer-runtime/cranelift", "wasmer-middleware-common-tests/clif", + "wasmer-runtime-core-tests/backend-cranelift", "wasmer-wasi-tests/clif" ] backend-llvm = [ @@ -91,6 +95,7 @@ backend-llvm = [ "wasmer-runtime-core/backend-llvm", "wasmer-runtime/llvm", "wasmer-middleware-common-tests/llvm", + "wasmer-runtime-core-tests/backend-llvm", "wasmer-wasi-tests/llvm" ] backend-singlepass = [ @@ -98,6 +103,7 @@ backend-singlepass = [ "wasmer-runtime-core/backend-singlepass", "wasmer-runtime/singlepass", "wasmer-middleware-common-tests/singlepass", + "wasmer-runtime-core-tests/backend-singlepass", "wasmer-wasi-tests/singlepass" ] wasi = ["wasmer-wasi"] diff --git a/lib/middleware-common-tests/Cargo.toml b/lib/middleware-common-tests/Cargo.toml index 5eb36d95905..d598f165c85 100644 --- a/lib/middleware-common-tests/Cargo.toml +++ b/lib/middleware-common-tests/Cargo.toml @@ -10,12 +10,13 @@ publish = false [dependencies] wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } wasmer-middleware-common = { path = "../middleware-common", version = "0.10.2" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.10.2" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.10.2", optional = true } wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.2", optional = true } wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.2", optional = true } [features] -clif = [] +default = ["clif"] +clif = ["wasmer-clif-backend"] llvm = ["wasmer-llvm-backend"] singlepass = ["wasmer-singlepass-backend"] diff --git a/lib/runtime-core-tests/Cargo.toml b/lib/runtime-core-tests/Cargo.toml index 0191d0e827f..b71ed2bb0d3 100644 --- a/lib/runtime-core-tests/Cargo.toml +++ b/lib/runtime-core-tests/Cargo.toml @@ -15,7 +15,7 @@ wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.2" wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.2", optional = true } [features] -default = ["backend-cranelift"] +default = [] backend-cranelift = ["wasmer-clif-backend"] backend-singlepass = ["wasmer-singlepass-backend"] backend-llvm = ["wasmer-llvm-backend"] diff --git a/lib/runtime/Cargo.toml b/lib/runtime/Cargo.toml index 902ea37ac38..8574d60a5c4 100644 --- a/lib/runtime/Cargo.toml +++ b/lib/runtime/Cargo.toml @@ -34,7 +34,7 @@ path = "../llvm-backend" optional = true [features] -default = ["cranelift", "default-backend-cranelift"] +default = ["cranelift"] cranelift = ["wasmer-clif-backend"] cache = ["cranelift"] debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"] diff --git a/lib/runtime/build.rs b/lib/runtime/build.rs new file mode 100644 index 00000000000..8f986c7546b --- /dev/null +++ b/lib/runtime/build.rs @@ -0,0 +1,38 @@ +//! This build script sets the default compiler using special output. +//! +//! See https://doc.rust-lang.org/cargo/reference/build-scripts.html +//! for details. + +/// This function tells Cargo which default backend to use +fn set_default_backend() { + // we must use this rather than `cfg` because the build.rs executes on the + // compiling system. This method works with cross compilation too. + match std::env::var("CARGO_CFG_TARGET_ARCH") + .expect("compilation target env var") + .as_ref() + { + "x86_64" => { + println!("cargo:rustc-cfg=feature=\"default-backend-cranelift\""); + } + "aarch64" => { + println!("cargo:rustc-cfg=feature=\"default-backend-singlepass\""); + } + other => { + println!("cargo:warning=compiling for untested architecture: \"{}\"! Attempting to use LLVM", other); + println!("cargo:rustc-cfg=feature=\"default-backend-llvm\""); + } + } +} + +/// This function checks if the user specified a default backend +fn has_default_backend() -> bool { + std::env::var("CARGO_FEATURE_DEFAULT_BACKEND_SINGLEPASS").is_ok() + || std::env::var("CARGO_FEATURE_DEFAULT_BACKEND_CRANELIFT").is_ok() + || std::env::var("CARGO_FEATURE_DEFAULT_BACKEND_LLVM").is_ok() +} + +fn main() { + if !has_default_backend() { + set_default_backend(); + } +} From 2154ba2ce70715f3e1f6b686f6f9dfdbc65040a6 Mon Sep 17 00:00:00 2001 From: Asami Doi Date: Fri, 22 Nov 2019 11:15:26 +0900 Subject: [PATCH 240/342] Fix no rule to make target 'wasi' --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 277b8a06964..f513663f5f1 100644 --- a/README.md +++ b/README.md @@ -235,7 +235,7 @@ Each integration can be tested separately: * Spec tests: `make spectests` * Emscripten: `make emtests` -* WASI: `make wasi` +* WASI: `make wasitests` * Middleware: `make middleware` * C API: `make capi` From bcdbdf4c23519b496c7ed1d5cebe96913d1508b5 Mon Sep 17 00:00:00 2001 From: Syrus Date: Thu, 21 Nov 2019 13:53:56 -0800 Subject: [PATCH 241/342] Updated Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index df85ffaa2e9..51c0983c848 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## **[Unreleased]** - [#995](https://github.com/wasmerio/wasmer/pull/995) Detect when a global is read without being initialized (emit a proper error instead of panicking) +- [#996](https://github.com/wasmerio/wasmer/pull/997) Refactored spectests, emtests and wasitests to use default compiler logic - [#992](https://github.com/wasmerio/wasmer/pull/992) Updates WAPM version to 0.4.1, fix arguments issue introduced in #990 - [#990](https://github.com/wasmerio/wasmer/pull/990) Default wasmer CLI to `run`. Wasmer will now attempt to parse unrecognized command line options as if they were applied to the run command: `wasmer mywasm.wasm --dir=.` now works! - [#987](https://github.com/wasmerio/wasmer/pull/987) Fix `runtime-c-api` header files when compiled by gnuc. From 7b9485320d472624f0282319fd930812d9bf2a73 Mon Sep 17 00:00:00 2001 From: Syrus Date: Thu, 21 Nov 2019 18:26:31 -0800 Subject: [PATCH 242/342] Revert "Autodetect default backend, add features for architecture type" This reverts commit 31437a1e749f8c0b2154ccbb3a5365c0ab7cdbab. --- Cargo.lock | 1 - Cargo.toml | 8 +----- lib/middleware-common-tests/Cargo.toml | 5 ++-- lib/runtime-core-tests/Cargo.toml | 2 +- lib/runtime/Cargo.toml | 2 +- lib/runtime/build.rs | 38 -------------------------- 6 files changed, 5 insertions(+), 51 deletions(-) delete mode 100644 lib/runtime/build.rs diff --git a/Cargo.lock b/Cargo.lock index 9db25328286..37410c3568b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1353,7 +1353,6 @@ dependencies = [ "wasmer-middleware-common-tests 0.10.2", "wasmer-runtime 0.10.2", "wasmer-runtime-core 0.10.2", - "wasmer-runtime-core-tests 0.10.2", "wasmer-singlepass-backend 0.10.2", "wasmer-wasi 0.10.2", "wasmer-wasi-tests 0.10.2", diff --git a/Cargo.toml b/Cargo.toml index 86d7152e37c..d3799f8e95c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,6 @@ wasmer-kernel-loader = { path = "lib/kernel-loader", optional = true } wasmer-dev-utils = { path = "lib/dev-utils", optional = true } wasmer-wasi-tests = { path = "lib/wasi-tests", optional = true } wasmer-middleware-common-tests = { path = "lib/middleware-common-tests", optional = true } -wasmer-runtime-core-tests = { path = "lib/runtime-core-tests", optional = true } wasmer-emscripten-tests = { path = "lib/emscripten-tests", optional = true } [workspace] @@ -74,10 +73,8 @@ serde = { version = "1", features = ["derive"] } # used by the plugin example typetag = "0.1" # used by the plugin example [features] -default = ["fast-tests", "wasi", "x86_64"] +default = ["fast-tests", "wasi", "backend-cranelift"] "loader-kernel" = ["wasmer-kernel-loader"] -aarch64 = ["backend-singlepass"] -x86_64 = ["backend-cranelift"] debug = ["wasmer-runtime-core/debug"] trace = ["wasmer-runtime-core/trace"] extra-debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"] @@ -87,7 +84,6 @@ backend-cranelift = [ "wasmer-runtime-core/backend-cranelift", "wasmer-runtime/cranelift", "wasmer-middleware-common-tests/clif", - "wasmer-runtime-core-tests/backend-cranelift", "wasmer-wasi-tests/clif" ] backend-llvm = [ @@ -95,7 +91,6 @@ backend-llvm = [ "wasmer-runtime-core/backend-llvm", "wasmer-runtime/llvm", "wasmer-middleware-common-tests/llvm", - "wasmer-runtime-core-tests/backend-llvm", "wasmer-wasi-tests/llvm" ] backend-singlepass = [ @@ -103,7 +98,6 @@ backend-singlepass = [ "wasmer-runtime-core/backend-singlepass", "wasmer-runtime/singlepass", "wasmer-middleware-common-tests/singlepass", - "wasmer-runtime-core-tests/backend-singlepass", "wasmer-wasi-tests/singlepass" ] wasi = ["wasmer-wasi"] diff --git a/lib/middleware-common-tests/Cargo.toml b/lib/middleware-common-tests/Cargo.toml index d598f165c85..5eb36d95905 100644 --- a/lib/middleware-common-tests/Cargo.toml +++ b/lib/middleware-common-tests/Cargo.toml @@ -10,13 +10,12 @@ publish = false [dependencies] wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } wasmer-middleware-common = { path = "../middleware-common", version = "0.10.2" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.10.2", optional = true } +wasmer-clif-backend = { path = "../clif-backend", version = "0.10.2" } wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.2", optional = true } wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.2", optional = true } [features] -default = ["clif"] -clif = ["wasmer-clif-backend"] +clif = [] llvm = ["wasmer-llvm-backend"] singlepass = ["wasmer-singlepass-backend"] diff --git a/lib/runtime-core-tests/Cargo.toml b/lib/runtime-core-tests/Cargo.toml index b71ed2bb0d3..0191d0e827f 100644 --- a/lib/runtime-core-tests/Cargo.toml +++ b/lib/runtime-core-tests/Cargo.toml @@ -15,7 +15,7 @@ wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.2" wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.2", optional = true } [features] -default = [] +default = ["backend-cranelift"] backend-cranelift = ["wasmer-clif-backend"] backend-singlepass = ["wasmer-singlepass-backend"] backend-llvm = ["wasmer-llvm-backend"] diff --git a/lib/runtime/Cargo.toml b/lib/runtime/Cargo.toml index 8574d60a5c4..902ea37ac38 100644 --- a/lib/runtime/Cargo.toml +++ b/lib/runtime/Cargo.toml @@ -34,7 +34,7 @@ path = "../llvm-backend" optional = true [features] -default = ["cranelift"] +default = ["cranelift", "default-backend-cranelift"] cranelift = ["wasmer-clif-backend"] cache = ["cranelift"] debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"] diff --git a/lib/runtime/build.rs b/lib/runtime/build.rs deleted file mode 100644 index 8f986c7546b..00000000000 --- a/lib/runtime/build.rs +++ /dev/null @@ -1,38 +0,0 @@ -//! This build script sets the default compiler using special output. -//! -//! See https://doc.rust-lang.org/cargo/reference/build-scripts.html -//! for details. - -/// This function tells Cargo which default backend to use -fn set_default_backend() { - // we must use this rather than `cfg` because the build.rs executes on the - // compiling system. This method works with cross compilation too. - match std::env::var("CARGO_CFG_TARGET_ARCH") - .expect("compilation target env var") - .as_ref() - { - "x86_64" => { - println!("cargo:rustc-cfg=feature=\"default-backend-cranelift\""); - } - "aarch64" => { - println!("cargo:rustc-cfg=feature=\"default-backend-singlepass\""); - } - other => { - println!("cargo:warning=compiling for untested architecture: \"{}\"! Attempting to use LLVM", other); - println!("cargo:rustc-cfg=feature=\"default-backend-llvm\""); - } - } -} - -/// This function checks if the user specified a default backend -fn has_default_backend() -> bool { - std::env::var("CARGO_FEATURE_DEFAULT_BACKEND_SINGLEPASS").is_ok() - || std::env::var("CARGO_FEATURE_DEFAULT_BACKEND_CRANELIFT").is_ok() - || std::env::var("CARGO_FEATURE_DEFAULT_BACKEND_LLVM").is_ok() -} - -fn main() { - if !has_default_backend() { - set_default_backend(); - } -} From 9a146c57fc43a0ad7c5e9715eb5700ad54710e33 Mon Sep 17 00:00:00 2001 From: Syrus Date: Thu, 21 Nov 2019 18:35:19 -0800 Subject: [PATCH 243/342] Make docs compilation happy --- Cargo.toml | 1 + Makefile | 2 +- lib/runtime/Cargo.toml | 1 + lib/runtime/src/lib.rs | 8 +++++--- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d3799f8e95c..7f879ec1ae9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,6 +77,7 @@ default = ["fast-tests", "wasi", "backend-cranelift"] "loader-kernel" = ["wasmer-kernel-loader"] debug = ["wasmer-runtime-core/debug"] trace = ["wasmer-runtime-core/trace"] +docs = ["wasmer-runtime/docs"] extra-debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"] # This feature will allow cargo test to run much faster fast-tests = [] diff --git a/Makefile b/Makefile index e8d11bed05e..11980bdd498 100644 --- a/Makefile +++ b/Makefile @@ -265,4 +265,4 @@ dep-graph: cargo deps --optional-deps --filter wasmer-wasi wasmer-wasi-tests wasmer-kernel-loader wasmer-dev-utils wasmer-llvm-backend wasmer-emscripten wasmer-emscripten-tests wasmer-runtime-core wasmer-runtime wasmer-middleware-common wasmer-middleware-common-tests wasmer-singlepass-backend wasmer-clif-backend wasmer --manifest-path Cargo.toml | dot -Tpng > wasmer_depgraph.png docs: - cargo doc --features=backend-singlepass,backend-llvm,wasi,managed + cargo doc --features=backend-cranelift,backend-singlepass,backend-llvm,docs,wasi,managed diff --git a/lib/runtime/Cargo.toml b/lib/runtime/Cargo.toml index 902ea37ac38..59392686f8f 100644 --- a/lib/runtime/Cargo.toml +++ b/lib/runtime/Cargo.toml @@ -35,6 +35,7 @@ optional = true [features] default = ["cranelift", "default-backend-cranelift"] +docs = [] cranelift = ["wasmer-clif-backend"] cache = ["cranelift"] debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"] diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index 4d3bf4c4f70..0f84a8194e2 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -208,12 +208,14 @@ pub fn default_compiler() -> impl Compiler { #[cfg(any( all( feature = "default-backend-llvm", + not(feature = "docs"), any( feature = "default-backend-cranelift", feature = "default-backend-singlepass" ) ), all( + not(feature = "docs"), feature = "default-backend-cranelift", feature = "default-backend-singlepass" ) @@ -222,13 +224,13 @@ pub fn default_compiler() -> impl Compiler { "The `default-backend-X` features are mutually exclusive. Please choose just one" ); - #[cfg(feature = "default-backend-llvm")] + #[cfg(all(feature = "default-backend-llvm", not(feature = "docs")))] use wasmer_llvm_backend::LLVMCompiler as DefaultCompiler; - #[cfg(feature = "default-backend-singlepass")] + #[cfg(all(feature = "default-backend-singlepass", not(feature = "docs")))] use wasmer_singlepass_backend::SinglePassCompiler as DefaultCompiler; - #[cfg(feature = "default-backend-cranelift")] + #[cfg(any(feature = "default-backend-singlepass", feature = "docs"))] use wasmer_clif_backend::CraneliftCompiler as DefaultCompiler; DefaultCompiler::new() From 27b6acdb16f85f45b8c03a05d1bafa0ee3da5101 Mon Sep 17 00:00:00 2001 From: Syrus Date: Thu, 21 Nov 2019 18:55:38 -0800 Subject: [PATCH 244/342] Fixed typo --- lib/runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index 0f84a8194e2..2ac6c174261 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -230,7 +230,7 @@ pub fn default_compiler() -> impl Compiler { #[cfg(all(feature = "default-backend-singlepass", not(feature = "docs")))] use wasmer_singlepass_backend::SinglePassCompiler as DefaultCompiler; - #[cfg(any(feature = "default-backend-singlepass", feature = "docs"))] + #[cfg(any(feature = "default-backend-cranelift", feature = "docs"))] use wasmer_clif_backend::CraneliftCompiler as DefaultCompiler; DefaultCompiler::new() From 499d42a759d97f5b44b5cffd452ec9e6548a0b35 Mon Sep 17 00:00:00 2001 From: Syrus Date: Thu, 21 Nov 2019 19:08:48 -0800 Subject: [PATCH 245/342] Fixed tests --- Cargo.toml | 3 --- Makefile | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7f879ec1ae9..13369c452c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,21 +85,18 @@ backend-cranelift = [ "wasmer-runtime-core/backend-cranelift", "wasmer-runtime/cranelift", "wasmer-middleware-common-tests/clif", - "wasmer-wasi-tests/clif" ] backend-llvm = [ "wasmer-llvm-backend", "wasmer-runtime-core/backend-llvm", "wasmer-runtime/llvm", "wasmer-middleware-common-tests/llvm", - "wasmer-wasi-tests/llvm" ] backend-singlepass = [ "wasmer-singlepass-backend", "wasmer-runtime-core/backend-singlepass", "wasmer-runtime/singlepass", "wasmer-middleware-common-tests/singlepass", - "wasmer-wasi-tests/singlepass" ] wasi = ["wasmer-wasi"] managed = ["backend-singlepass", "wasmer-runtime-core/managed"] diff --git a/Makefile b/Makefile index 11980bdd498..ad8b762c3c6 100644 --- a/Makefile +++ b/Makefile @@ -220,13 +220,13 @@ check: check-bench # Release release: - cargo build --release --features backend-singlepass,backend-llvm,loader-kernel + cargo build --release --features backend-singlepass,backend-cranelift,backend-llvm,loader-kernel # Only one backend (cranelift) release-clif: # If you are on macOS, you will need mingw-w64 for cross compiling to Windows # brew install mingw-w64 - cargo build --release + cargo build --release --features backend-cranelift release-singlepass: cargo build --release --features backend-singlepass From 180528241d9586c40399cc5f5e10de5dcbd5c52d Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 21 Nov 2019 19:31:17 -0800 Subject: [PATCH 246/342] Fix merge issue in wasi tests --- lib/wasi-tests/tests/wasitests/_common.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/wasi-tests/tests/wasitests/_common.rs b/lib/wasi-tests/tests/wasitests/_common.rs index c5bc80c0974..41bf14e44b4 100644 --- a/lib/wasi-tests/tests/wasitests/_common.rs +++ b/lib/wasi-tests/tests/wasitests/_common.rs @@ -1,7 +1,7 @@ macro_rules! assert_wasi_output { ($file:expr, $name:expr, $po_dir_args: expr, $mapdir_args:expr, $envvar_args:expr, $expected:expr) => {{ use wasmer_dev_utils::stdio::StdioCapturer; - use wasmer_runtime_core::Func; + use wasmer_runtime::Func; use wasmer_wasi::{generate_import_object_for_version, get_wasi_version}; let wasm_bytes = include_bytes!($file); From 9fe5e261ea407da5a6dee7b6f758bef82578e61b Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 21 Nov 2019 22:41:23 -0800 Subject: [PATCH 247/342] Update the LLVM pass list. Adds optimizations of loops, and inlinling and some simple interprocedural optimization. --- lib/llvm-backend/src/code.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 0aca846505c..4785cb56987 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -8290,21 +8290,37 @@ impl ModuleCodeGenerator pass_manager.add_verifier_pass(); } pass_manager.add_type_based_alias_analysis_pass(); + pass_manager.add_ipsccp_pass(); + pass_manager.add_prune_eh_pass(); + pass_manager.add_dead_arg_elimination_pass(); + pass_manager.add_function_inlining_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_gvn_pass(); pass_manager.add_jump_threading_pass(); pass_manager.add_correlated_value_propagation_pass(); - pass_manager.add_sccp_pass(); + pass_manager.add_cfg_simplification_pass(); + pass_manager.add_reassociate_pass(); + pass_manager.add_loop_rotate_pass(); + pass_manager.add_loop_unswitch_pass(); + pass_manager.add_ind_var_simplify_pass(); + pass_manager.add_licm_pass(); + pass_manager.add_loop_vectorize_pass(); pass_manager.add_instruction_combining_pass(); + pass_manager.add_ipsccp_pass(); pass_manager.add_reassociate_pass(); pass_manager.add_cfg_simplification_pass(); + pass_manager.add_gvn_pass(); + pass_manager.add_memcpy_optimize_pass(); + pass_manager.add_dead_store_elimination_pass(); pass_manager.add_bit_tracking_dce_pass(); + pass_manager.add_instruction_combining_pass(); + pass_manager.add_reassociate_pass(); + pass_manager.add_cfg_simplification_pass(); pass_manager.add_slp_vectorize_pass(); - pass_manager.run_on(&*self.module.borrow_mut()); + pass_manager.add_early_cse_pass(); + pass_manager.run_on(&*self.module.borrow_mut()); if let Some(path) = unsafe { &crate::GLOBAL_OPTIONS.post_opt_ir } { self.module.borrow_mut().print_to_file(path).unwrap(); } From 21e676667e5401cd3ba6b084c256dc5b22c223c2 Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 22 Nov 2019 23:37:06 +0800 Subject: [PATCH 248/342] Try pinning Rust version for arm64 build. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ab8b1c4f2df..9fc755d3acc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ arch: language: rust rust: - - nightly + - nightly-2019-08-15 cache: directories: From 508004088e418586aa6f4c3d3bec37c494ef055c Mon Sep 17 00:00:00 2001 From: Patrick Ventuzelo Date: Fri, 22 Nov 2019 17:10:54 +0100 Subject: [PATCH 249/342] check stack len before getting value --- lib/llvm-backend/src/state.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/llvm-backend/src/state.rs b/lib/llvm-backend/src/state.rs index 0d46dc5c099..486cc93572c 100644 --- a/lib/llvm-backend/src/state.rs +++ b/lib/llvm-backend/src/state.rs @@ -240,12 +240,16 @@ impl State { &self, n: usize, ) -> Result<&[(BasicValueEnum, ExtraInfo)], BinaryReaderError> { - self.stack - .get(self.stack.len() - n..) - .ok_or(BinaryReaderError { + if self.stack.len() < n { + return Err(BinaryReaderError { message: "invalid value stack", offset: -1isize as usize, - }) + }); + } + + let new_len = self.stack.len() - n; + Ok(&self.stack[new_len..]) + } pub fn popn_save_extra( From 2261f8b449746ed70231d5b8290990af0d2f5f0c Mon Sep 17 00:00:00 2001 From: Patrick Ventuzelo Date: Fri, 22 Nov 2019 17:21:15 +0100 Subject: [PATCH 250/342] cargo fmt --- lib/llvm-backend/src/state.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/llvm-backend/src/state.rs b/lib/llvm-backend/src/state.rs index 486cc93572c..5f70bb3c580 100644 --- a/lib/llvm-backend/src/state.rs +++ b/lib/llvm-backend/src/state.rs @@ -249,7 +249,6 @@ impl State { let new_len = self.stack.len() - n; Ok(&self.stack[new_len..]) - } pub fn popn_save_extra( From cd0da74b333fa96e9195c43c7191ffd7ebe02a75 Mon Sep 17 00:00:00 2001 From: Patrick Ventuzelo Date: Fri, 22 Nov 2019 17:25:17 +0100 Subject: [PATCH 251/342] add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51c0983c848..a9869eab32e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## **[Unreleased]** +- [#1006](https://github.com/wasmerio/wasmer/pull/1006) Fix minor panic issue when `wasmer::compile_with` called with llvm backend - [#995](https://github.com/wasmerio/wasmer/pull/995) Detect when a global is read without being initialized (emit a proper error instead of panicking) - [#996](https://github.com/wasmerio/wasmer/pull/997) Refactored spectests, emtests and wasitests to use default compiler logic - [#992](https://github.com/wasmerio/wasmer/pull/992) Updates WAPM version to 0.4.1, fix arguments issue introduced in #990 From a691d3454c2540a16b37812551e629e18228e497 Mon Sep 17 00:00:00 2001 From: Syrus Date: Thu, 21 Nov 2019 20:20:12 -0800 Subject: [PATCH 252/342] Skip serializing on singlepass --- lib/wasi-tests/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/wasi-tests/src/lib.rs b/lib/wasi-tests/src/lib.rs index 3801e069321..dcfa5bc8b47 100644 --- a/lib/wasi-tests/src/lib.rs +++ b/lib/wasi-tests/src/lib.rs @@ -4,6 +4,7 @@ use wasmer_wasi::{state::*, *}; use std::ffi::c_void; +#[cfg(not(feature = "singlepass"))] #[test] fn serializing_works() { let args = vec![ From 183dd328d6428a5dd92969304350dfb31085c61c Mon Sep 17 00:00:00 2001 From: Syrus Date: Fri, 22 Nov 2019 09:55:31 -0800 Subject: [PATCH 253/342] Make travis work only on test branches --- .travis.yml | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9fc755d3acc..0e6f71c7ef2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,6 +24,7 @@ script: # Tests - make spectests-singlepass +before_deploy: # Release - make release-singlepass - make wapm @@ -31,12 +32,12 @@ script: - mkdir -p artifacts - cp ./wasmer.tar.gz ./artifacts/$(./scripts/binary-name.sh) -before_deploy: - # Set up git user name and tag this commit - - git config --local user.name "Syrus Akbary" - - git config --local user.email "syrus@wasmer.io" - - export TRAVIS_TAG="0.10.2" - # - git tag $TRAVIS_TAG +# before_deploy: +# # Set up git user name and tag this commit +# - git config --local user.name "Syrus Akbary" +# - git config --local user.email "syrus@wasmer.io" +# - export TRAVIS_TAG="0.10.2" +# # - git tag $TRAVIS_TAG deploy: provider: releases @@ -46,8 +47,8 @@ deploy: # This is set to the previous artifacts are not deleted by travis skip_cleanup: true on: - branch: feature/singlepass-aarch64 - + tags: true + # branch: feature/singlepass-aarch64 addons: apt: @@ -56,4 +57,6 @@ addons: branches: only: - - feature/singlepass-aarch64 \ No newline at end of file + - master + - staging + - trying From bb1e7a8d78018c8576674828d87df38555a8b972 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Fri, 22 Nov 2019 11:18:06 -0800 Subject: [PATCH 254/342] Prepare for 0.11.0 release --- CHANGELOG.md | 2 + Cargo.lock | 144 ++++++++++++------------- 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 | 8 +- lib/runtime-core-tests/Cargo.toml | 10 +- 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 | 14 +-- lib/wasi/Cargo.toml | 6 +- lib/win-exception-handler/Cargo.toml | 4 +- scripts/update_version_numbers.sh | 4 +- src/installer/wasmer.iss | 2 +- 21 files changed, 134 insertions(+), 132 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c200b192c5..1e99bc60d32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## **[Unreleased]** +## 0.11.0 - 2019-11-22 + - [#713](https://github.com/wasmerio/wasmer/pull/713) Add AArch64 support for singlepass. - [#995](https://github.com/wasmerio/wasmer/pull/995) Detect when a global is read without being initialized (emit a proper error instead of panicking) - [#996](https://github.com/wasmerio/wasmer/pull/997) Refactored spectests, emtests and wasitests to use default compiler logic diff --git a/Cargo.lock b/Cargo.lock index e21ab6c531a..b628e7cdc1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -717,8 +717,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.10.2", - "wasmer-runtime-core 0.10.2", + "wasmer-runtime 0.11.0", + "wasmer-runtime-core 0.11.0", ] [[package]] @@ -1328,7 +1328,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wasmer" -version = "0.10.2" +version = "0.11.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)", @@ -1338,24 +1338,24 @@ dependencies = [ "structopt 0.3.4 (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.10.2", - "wasmer-dev-utils 0.10.2", - "wasmer-emscripten 0.10.2", - "wasmer-emscripten-tests 0.10.2", + "wasmer-clif-backend 0.11.0", + "wasmer-dev-utils 0.11.0", + "wasmer-emscripten 0.11.0", + "wasmer-emscripten-tests 0.11.0", "wasmer-kernel-loader 0.1.0", - "wasmer-llvm-backend 0.10.2", - "wasmer-middleware-common 0.10.2", - "wasmer-middleware-common-tests 0.10.2", - "wasmer-runtime 0.10.2", - "wasmer-runtime-core 0.10.2", - "wasmer-singlepass-backend 0.10.2", - "wasmer-wasi 0.10.2", - "wasmer-wasi-tests 0.10.2", + "wasmer-llvm-backend 0.11.0", + "wasmer-middleware-common 0.11.0", + "wasmer-middleware-common-tests 0.11.0", + "wasmer-runtime 0.11.0", + "wasmer-runtime-core 0.11.0", + "wasmer-singlepass-backend 0.11.0", + "wasmer-wasi 0.11.0", + "wasmer-wasi-tests 0.11.0", ] [[package]] name = "wasmer-clif-backend" -version = "0.10.2" +version = "0.11.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)", @@ -1371,8 +1371,8 @@ 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.10.2", - "wasmer-win-exception-handler 0.10.2", + "wasmer-runtime-core 0.11.0", + "wasmer-win-exception-handler 0.11.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)", ] @@ -1404,35 +1404,35 @@ dependencies = [ [[package]] name = "wasmer-dev-utils" -version = "0.10.2" +version = "0.11.0" dependencies = [ "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmer-emscripten" -version = "0.10.2" +version = "0.11.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)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.10.2", + "wasmer-runtime-core 0.11.0", ] [[package]] name = "wasmer-emscripten-tests" -version = "0.10.2" +version = "0.11.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.10.2", - "wasmer-dev-utils 0.10.2", - "wasmer-emscripten 0.10.2", - "wasmer-llvm-backend 0.10.2", - "wasmer-runtime 0.10.2", - "wasmer-singlepass-backend 0.10.2", + "wasmer-clif-backend 0.11.0", + "wasmer-dev-utils 0.11.0", + "wasmer-emscripten 0.11.0", + "wasmer-llvm-backend 0.11.0", + "wasmer-runtime 0.11.0", + "wasmer-singlepass-backend 0.11.0", ] [[package]] @@ -1440,12 +1440,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.10.2", + "wasmer-runtime-core 0.11.0", ] [[package]] name = "wasmer-llvm-backend" -version = "0.10.2" +version = "0.11.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1459,60 +1459,60 @@ dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.13 (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.10.2", + "wasmer-runtime-core 0.11.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.10.2" +version = "0.11.0" dependencies = [ - "wasmer-runtime-core 0.10.2", + "wasmer-runtime-core 0.11.0", ] [[package]] name = "wasmer-middleware-common-tests" -version = "0.10.2" +version = "0.11.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.10.2", - "wasmer-llvm-backend 0.10.2", - "wasmer-middleware-common 0.10.2", - "wasmer-runtime-core 0.10.2", - "wasmer-singlepass-backend 0.10.2", + "wasmer-clif-backend 0.11.0", + "wasmer-llvm-backend 0.11.0", + "wasmer-middleware-common 0.11.0", + "wasmer-runtime-core 0.11.0", + "wasmer-singlepass-backend 0.11.0", ] [[package]] name = "wasmer-runtime" -version = "0.10.2" +version = "0.11.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.10.2", - "wasmer-llvm-backend 0.10.2", - "wasmer-runtime-core 0.10.2", - "wasmer-singlepass-backend 0.10.2", + "wasmer-clif-backend 0.11.0", + "wasmer-llvm-backend 0.11.0", + "wasmer-runtime-core 0.11.0", + "wasmer-singlepass-backend 0.11.0", ] [[package]] name = "wasmer-runtime-c-api" -version = "0.10.2" +version = "0.11.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.10.2", - "wasmer-runtime-core 0.10.2", - "wasmer-wasi 0.10.2", + "wasmer-runtime 0.11.0", + "wasmer-runtime-core 0.11.0", + "wasmer-wasi 0.11.0", ] [[package]] name = "wasmer-runtime-core" -version = "0.10.2" +version = "0.11.0" dependencies = [ "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "blake2b_simd 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1538,18 +1538,18 @@ dependencies = [ [[package]] name = "wasmer-runtime-core-tests" -version = "0.10.2" +version = "0.11.0" dependencies = [ "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-clif-backend 0.10.2", - "wasmer-llvm-backend 0.10.2", - "wasmer-runtime-core 0.10.2", - "wasmer-singlepass-backend 0.10.2", + "wasmer-clif-backend 0.11.0", + "wasmer-llvm-backend 0.11.0", + "wasmer-runtime-core 0.11.0", + "wasmer-singlepass-backend 0.11.0", ] [[package]] name = "wasmer-singlepass-backend" -version = "0.10.2" +version = "0.11.0" dependencies = [ "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)", @@ -1558,24 +1558,24 @@ 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.13 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.10.2", + "wasmer-runtime-core 0.11.0", ] [[package]] name = "wasmer-spectests" -version = "0.10.2" +version = "0.11.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.10.2", - "wasmer-llvm-backend 0.10.2", - "wasmer-runtime 0.10.2", - "wasmer-singlepass-backend 0.10.2", + "wasmer-clif-backend 0.11.0", + "wasmer-llvm-backend 0.11.0", + "wasmer-runtime 0.11.0", + "wasmer-singlepass-backend 0.11.0", ] [[package]] name = "wasmer-wasi" -version = "0.10.2" +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)", @@ -1586,30 +1586,30 @@ dependencies = [ "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.10.2", + "wasmer-runtime-core 0.11.0", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmer-wasi-tests" -version = "0.10.2" +version = "0.11.0" dependencies = [ "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-clif-backend 0.10.2", - "wasmer-dev-utils 0.10.2", - "wasmer-llvm-backend 0.10.2", - "wasmer-runtime 0.10.2", - "wasmer-singlepass-backend 0.10.2", - "wasmer-wasi 0.10.2", + "wasmer-clif-backend 0.11.0", + "wasmer-dev-utils 0.11.0", + "wasmer-llvm-backend 0.11.0", + "wasmer-runtime 0.11.0", + "wasmer-singlepass-backend 0.11.0", + "wasmer-wasi 0.11.0", ] [[package]] name = "wasmer-win-exception-handler" -version = "0.10.2" +version = "0.11.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.10.2", + "wasmer-runtime-core 0.11.0", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/Cargo.toml b/Cargo.toml index c9cc342d9b8..22d436401c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer" -version = "0.10.2" +version = "0.11.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 e3d5689749d..1dea62a2415 100644 --- a/lib/clif-backend/Cargo.toml +++ b/lib/clif-backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-clif-backend" -version = "0.10.2" +version = "0.11.0" description = "Wasmer runtime Cranelift compiler backend" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -11,7 +11,7 @@ edition = "2018" readme = "README.md" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.11.0" } cranelift-native = "0.44.0" cranelift-codegen = "0.44.0" cranelift-entity = "0.44.0" @@ -37,7 +37,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.10.2" } +wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.11.0" } [features] debug = ["wasmer-runtime-core/debug"] diff --git a/lib/dev-utils/Cargo.toml b/lib/dev-utils/Cargo.toml index 45722b9b6b0..81fb49757d7 100644 --- a/lib/dev-utils/Cargo.toml +++ b/lib/dev-utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-dev-utils" -version = "0.10.2" +version = "0.11.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 6be2a3056eb..39700ab2198 100644 --- a/lib/emscripten-tests/Cargo.toml +++ b/lib/emscripten-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-emscripten-tests" -version = "0.10.2" +version = "0.11.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.10.2" } -wasmer-runtime = { path = "../runtime", version = "0.10.2", default-features = false } -wasmer-clif-backend = { path = "../clif-backend", version = "0.10.2", optional = true} -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.2", optional = true } -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.2", optional = true } +wasmer-emscripten = { path = "../emscripten", version = "0.11.0" } +wasmer-runtime = { path = "../runtime", version = "0.11.0", default-features = false } +wasmer-clif-backend = { path = "../clif-backend", version = "0.11.0", optional = true} +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.11.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.11.0", optional = true } [dev-dependencies] wabt = "0.9.1" -wasmer-dev-utils = { path = "../dev-utils", version = "0.10.2"} +wasmer-dev-utils = { path = "../dev-utils", version = "0.11.0"} [build-dependencies] glob = "0.3" diff --git a/lib/emscripten/Cargo.toml b/lib/emscripten/Cargo.toml index 27606a1538c..dffbe09422b 100644 --- a/lib/emscripten/Cargo.toml +++ b/lib/emscripten/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-emscripten" -version = "0.10.2" +version = "0.11.0" description = "Wasmer runtime emscripten implementation library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -14,7 +14,7 @@ byteorder = "1.3" lazy_static = "1.4" libc = "0.2.60" time = "0.1" -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.11.0" } [target.'cfg(windows)'.dependencies] getrandom = "0.1" diff --git a/lib/llvm-backend/Cargo.toml b/lib/llvm-backend/Cargo.toml index c3fe61811ff..24a3f082f85 100644 --- a/lib/llvm-backend/Cargo.toml +++ b/lib/llvm-backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-llvm-backend" -version = "0.10.2" +version = "0.11.0" license = "MIT" authors = ["The Wasmer Engineering Team "] repository = "https://github.com/wasmerio/wasmer" @@ -10,7 +10,7 @@ edition = "2018" readme = "README.md" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.11.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 5eb36d95905..1ed0fccdbd6 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.10.2" +version = "0.11.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.10.2" } -wasmer-middleware-common = { path = "../middleware-common", version = "0.10.2" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.10.2" } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.2", optional = true } -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.2", optional = true } +wasmer-runtime-core = { path = "../runtime-core", version = "0.11.0" } +wasmer-middleware-common = { path = "../middleware-common", version = "0.11.0" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.11.0" } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.11.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.11.0", optional = true } [features] clif = [] diff --git a/lib/middleware-common/Cargo.toml b/lib/middleware-common/Cargo.toml index e151c7f3b38..3cddcefcc90 100644 --- a/lib/middleware-common/Cargo.toml +++ b/lib/middleware-common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-middleware-common" -version = "0.10.2" +version = "0.11.0" repository = "https://github.com/wasmerio/wasmer" description = "Wasmer runtime common middlewares" license = "MIT" @@ -10,4 +10,4 @@ categories = ["wasm"] edition = "2018" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.11.0" } diff --git a/lib/runtime-c-api/Cargo.toml b/lib/runtime-c-api/Cargo.toml index cae6cd7441e..0a278b6ba2e 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.10.2" +version = "0.11.0" description = "Wasmer C API library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -19,17 +19,17 @@ libc = "0.2.60" [dependencies.wasmer-runtime] default-features = false path = "../runtime" -version = "0.10.2" +version = "0.11.0" [dependencies.wasmer-runtime-core] default-features = false path = "../runtime-core" -version = "0.10.2" +version = "0.11.0" [dependencies.wasmer-wasi] default-features = false path = "../wasi" -version = "0.10.2" +version = "0.11.0" optional = true [features] diff --git a/lib/runtime-core-tests/Cargo.toml b/lib/runtime-core-tests/Cargo.toml index 0191d0e827f..c844b3f164a 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.10.2" +version = "0.11.0" description = "Tests for the Wasmer runtime core crate" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -9,10 +9,10 @@ publish = false [dependencies] wabt = "0.9.1" -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.10.2", optional = true } -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.2", optional = true } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.2", optional = true } +wasmer-runtime-core = { path = "../runtime-core", version = "0.11.0" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.11.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.11.0", optional = true } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.11.0", optional = true } [features] default = ["backend-cranelift"] diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml index e269ad15a0a..7c76d74ac45 100644 --- a/lib/runtime-core/Cargo.toml +++ b/lib/runtime-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-runtime-core" -version = "0.10.2" +version = "0.11.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 59392686f8f..e6fe8bb9b18 100644 --- a/lib/runtime/Cargo.toml +++ b/lib/runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-runtime" -version = "0.10.2" +version = "0.11.0" description = "Wasmer runtime library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -11,17 +11,17 @@ edition = "2018" readme = "README.md" [dependencies] -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.2", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.11.0", optional = true } lazy_static = "1.4" memmap = "0.7" [dependencies.wasmer-runtime-core] path = "../runtime-core" -version = "0.10.2" +version = "0.11.0" [dependencies.wasmer-clif-backend] path = "../clif-backend" -version = "0.10.2" +version = "0.11.0" optional = true [dev-dependencies] diff --git a/lib/singlepass-backend/Cargo.toml b/lib/singlepass-backend/Cargo.toml index 292b7038f02..81f006049e9 100644 --- a/lib/singlepass-backend/Cargo.toml +++ b/lib/singlepass-backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-singlepass-backend" -version = "0.10.2" +version = "0.11.0" repository = "https://github.com/wasmerio/wasmer" description = "Wasmer runtime single pass compiler backend" license = "MIT" @@ -11,7 +11,7 @@ edition = "2018" readme = "README.md" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.11.0" } dynasm = "0.5" dynasmrt = "0.5" lazy_static = "1.4" diff --git a/lib/spectests/Cargo.toml b/lib/spectests/Cargo.toml index fe02bec5d24..ea49633ada0 100644 --- a/lib/spectests/Cargo.toml +++ b/lib/spectests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-spectests" -version = "0.10.2" +version = "0.11.0" description = "Wasmer spectests library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -9,10 +9,10 @@ edition = "2018" [dependencies] glob = "0.3" -wasmer-runtime = { path = "../runtime", version = "0.10.2", default-features = false} -wasmer-clif-backend = { path = "../clif-backend", version = "0.10.2", optional = true} -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.2", optional = true } -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.2", optional = true } +wasmer-runtime = { path = "../runtime", version = "0.11.0", default-features = false} +wasmer-clif-backend = { path = "../clif-backend", version = "0.11.0", optional = true} +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.11.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.11.0", optional = true } [build-dependencies] wabt = "0.9.1" diff --git a/lib/wasi-tests/Cargo.toml b/lib/wasi-tests/Cargo.toml index fa81d0fc114..654921e373b 100644 --- a/lib/wasi-tests/Cargo.toml +++ b/lib/wasi-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-wasi-tests" -version = "0.10.2" +version = "0.11.0" description = "Tests for our WASI implementation" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -10,18 +10,18 @@ build = "build/mod.rs" [dependencies] # We set default features to false to be able to use the singlepass backend properly -wasmer-runtime = { path = "../runtime", version = "0.10.2", default-features = false } -wasmer-wasi = { path = "../wasi", version = "0.10.2" } +wasmer-runtime = { path = "../runtime", version = "0.11.0", default-features = false } +wasmer-wasi = { path = "../wasi", version = "0.11.0" } # hack to get tests to work -wasmer-clif-backend = { path = "../clif-backend", version = "0.10.2", optional = true} -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.10.2", optional = true } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.10.2", optional = true } +wasmer-clif-backend = { path = "../clif-backend", version = "0.11.0", optional = true} +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.11.0", optional = true } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.11.0", optional = true } [build-dependencies] glob = "0.3" [dev-dependencies] -wasmer-dev-utils = { path = "../dev-utils", version = "0.10.2"} +wasmer-dev-utils = { path = "../dev-utils", version = "0.11.0"} [features] clif = ["wasmer-clif-backend", "wasmer-runtime/default-backend-cranelift"] diff --git a/lib/wasi/Cargo.toml b/lib/wasi/Cargo.toml index 4eb5dc95ea1..f118c1b1cf7 100644 --- a/lib/wasi/Cargo.toml +++ b/lib/wasi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-wasi" -version = "0.10.2" +version = "0.11.0" description = "Wasmer runtime WASI implementation library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -19,7 +19,7 @@ getrandom = "0.1" time = "0.1" typetag = "0.1" serde = { version = "1", features = ["derive"] } -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.11.0" } [target.'cfg(windows)'.dependencies] -winapi = "0.3" \ No newline at end of file +winapi = "0.3" diff --git a/lib/win-exception-handler/Cargo.toml b/lib/win-exception-handler/Cargo.toml index ef1cf619a90..17f89a0a68d 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.10.2" +version = "0.11.0" description = "Wasmer runtime exception handling for Windows" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -8,7 +8,7 @@ repository = "https://github.com/wasmerio/wasmer" edition = "2018" [target.'cfg(windows)'.dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.10.2" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.11.0" } winapi = { version = "0.3.8", features = ["winbase", "errhandlingapi", "minwindef", "minwinbase", "winnt"] } libc = "0.2.60" diff --git a/scripts/update_version_numbers.sh b/scripts/update_version_numbers.sh index 2ee5bb0823e..af1485a3f06 100755 --- a/scripts/update_version_numbers.sh +++ b/scripts/update_version_numbers.sh @@ -1,5 +1,5 @@ -PREVIOUS_VERSION='0.10.1' -NEXT_VERSION='0.10.2' +PREVIOUS_VERSION='0.10.2' +NEXT_VERSION='0.11.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 146680b05ac..0fd5cf639fe 100644 --- a/src/installer/wasmer.iss +++ b/src/installer/wasmer.iss @@ -1,6 +1,6 @@ [Setup] AppName=Wasmer -AppVersion=0.10.2 +AppVersion=0.11.0 DefaultDirName={pf}\Wasmer DefaultGroupName=Wasmer Compression=lzma2 From 8f50dab0f290f949287b1f279bd512b122e74951 Mon Sep 17 00:00:00 2001 From: Syrus Date: Fri, 22 Nov 2019 12:23:11 -0800 Subject: [PATCH 255/342] Trying to improve release process --- .travis.yml | 3 +++ azure-pipelines.yml | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0e6f71c7ef2..4dbbd44d8e3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -60,3 +60,6 @@ branches: - master - staging - trying + # Making sure Travis runs on new Tags + - /^\d+\.\d+(\.\d+)?(-\S*)?$/ + - /^v\d+\.\d+(\.\d+)?(-\S*)?$/ diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 720115f1828..77337a3241c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -104,7 +104,7 @@ jobs: # RUSTFLAGS: -Ctarget-feature=+crt-static pool: vmImage: $(imageName) - condition: in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying') + condition: or(in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying'), startsWith(variables['Build.SourceBranch'], 'refs/tags')) steps: - checkout: self submodules: true @@ -167,7 +167,7 @@ jobs: # RUSTFLAGS: -Ctarget-feature=+crt-static pool: vmImage: $(imageName) - condition: in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying') + condition: or(in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying'), startsWith(variables['Build.SourceBranch'], 'refs/tags')) steps: - checkout: self submodules: true From 2433d365afe7ec7906bd51f33cd601036ba7aab9 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 22 Nov 2019 16:32:02 -0800 Subject: [PATCH 256/342] Add new test feature, enabled in test crates. When test feature is enabled, turn on LLVM verifier. This was previously never enabled. --- lib/emscripten-tests/Cargo.toml | 2 +- lib/llvm-backend/Cargo.toml | 1 + lib/llvm-backend/src/code.rs | 7 ++++--- lib/middleware-common-tests/Cargo.toml | 2 +- lib/runtime-core-tests/Cargo.toml | 2 +- lib/spectests/Cargo.toml | 2 +- lib/wasi-tests/Cargo.toml | 2 +- 7 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/emscripten-tests/Cargo.toml b/lib/emscripten-tests/Cargo.toml index 39700ab2198..2439b429578 100644 --- a/lib/emscripten-tests/Cargo.toml +++ b/lib/emscripten-tests/Cargo.toml @@ -12,7 +12,7 @@ build = "build/mod.rs" wasmer-emscripten = { path = "../emscripten", version = "0.11.0" } wasmer-runtime = { path = "../runtime", version = "0.11.0", default-features = false } wasmer-clif-backend = { path = "../clif-backend", version = "0.11.0", optional = true} -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.11.0", optional = true } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.11.0", optional = true, features = ["test"] } wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.11.0", optional = true } [dev-dependencies] diff --git a/lib/llvm-backend/Cargo.toml b/lib/llvm-backend/Cargo.toml index 24a3f082f85..2f5db92de99 100644 --- a/lib/llvm-backend/Cargo.toml +++ b/lib/llvm-backend/Cargo.toml @@ -41,3 +41,4 @@ wabt = "0.9.1" [features] debug = ["wasmer-runtime-core/debug"] +test = [] diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 0aca846505c..63efc3148f7 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -8286,9 +8286,10 @@ impl ModuleCodeGenerator } let pass_manager = PassManager::create(()); - if cfg!(test) { - pass_manager.add_verifier_pass(); - } + + #[cfg(feature = "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(); diff --git a/lib/middleware-common-tests/Cargo.toml b/lib/middleware-common-tests/Cargo.toml index 1ed0fccdbd6..1541a096cf6 100644 --- a/lib/middleware-common-tests/Cargo.toml +++ b/lib/middleware-common-tests/Cargo.toml @@ -11,7 +11,7 @@ publish = false wasmer-runtime-core = { path = "../runtime-core", version = "0.11.0" } wasmer-middleware-common = { path = "../middleware-common", version = "0.11.0" } wasmer-clif-backend = { path = "../clif-backend", version = "0.11.0" } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.11.0", optional = true } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.11.0", features = ["test"], optional = true } wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.11.0", optional = true } [features] diff --git a/lib/runtime-core-tests/Cargo.toml b/lib/runtime-core-tests/Cargo.toml index c844b3f164a..57e9e19f9cb 100644 --- a/lib/runtime-core-tests/Cargo.toml +++ b/lib/runtime-core-tests/Cargo.toml @@ -12,7 +12,7 @@ wabt = "0.9.1" wasmer-runtime-core = { path = "../runtime-core", version = "0.11.0" } wasmer-clif-backend = { path = "../clif-backend", version = "0.11.0", optional = true } wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.11.0", optional = true } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.11.0", optional = true } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.11.0", features = ["test"], optional = true } [features] default = ["backend-cranelift"] diff --git a/lib/spectests/Cargo.toml b/lib/spectests/Cargo.toml index ea49633ada0..81bd57669e8 100644 --- a/lib/spectests/Cargo.toml +++ b/lib/spectests/Cargo.toml @@ -11,7 +11,7 @@ edition = "2018" glob = "0.3" wasmer-runtime = { path = "../runtime", version = "0.11.0", default-features = false} wasmer-clif-backend = { path = "../clif-backend", version = "0.11.0", optional = true} -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.11.0", optional = true } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.11.0", features = ["test"], optional = true } wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.11.0", optional = true } [build-dependencies] diff --git a/lib/wasi-tests/Cargo.toml b/lib/wasi-tests/Cargo.toml index 654921e373b..9b84e5ea91e 100644 --- a/lib/wasi-tests/Cargo.toml +++ b/lib/wasi-tests/Cargo.toml @@ -15,7 +15,7 @@ wasmer-wasi = { path = "../wasi", version = "0.11.0" } # hack to get tests to work wasmer-clif-backend = { path = "../clif-backend", version = "0.11.0", optional = true} wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.11.0", optional = true } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.11.0", optional = true } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.11.0", features = ["test"], optional = true } [build-dependencies] glob = "0.3" From 85666fc52250c89e13c0cec315dad12362bf7b84 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 22 Nov 2019 16:33:16 -0800 Subject: [PATCH 257/342] Add new llvm-backend-test crate. --- Cargo.lock | 10 ++++++++++ Cargo.toml | 1 + Makefile | 1 + lib/llvm-backend-tests/Cargo.toml | 15 +++++++++++++++ lib/llvm-backend-tests/src/lib.rs | 7 +++++++ lib/llvm-backend-tests/tests/compile.rs | 22 ++++++++++++++++++++++ 6 files changed, 56 insertions(+) create mode 100644 lib/llvm-backend-tests/Cargo.toml create mode 100644 lib/llvm-backend-tests/src/lib.rs create mode 100644 lib/llvm-backend-tests/tests/compile.rs diff --git a/Cargo.lock b/Cargo.lock index b628e7cdc1f..c92d5ceb1c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1464,6 +1464,16 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "wasmer-llvm-backend-tests" +version = "0.10.2" +dependencies = [ + "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmer-llvm-backend 0.11.0", + "wasmer-runtime 0.11.0", + "wasmer-runtime-core 0.11.0", +] + [[package]] name = "wasmer-middleware-common" version = "0.11.0" diff --git a/Cargo.toml b/Cargo.toml index 22d436401c6..557fade49e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,7 @@ members = [ "lib/win-exception-handler", "lib/runtime-c-api", "lib/llvm-backend", + "lib/llvm-backend-tests", "lib/wasi", "lib/middleware-common", "lib/kernel-loader", diff --git a/Makefile b/Makefile index 07e595e4487..4acde792584 100644 --- a/Makefile +++ b/Makefile @@ -97,6 +97,7 @@ cranelift: spectests-cranelift emtests-cranelift middleware-cranelift wasitests- llvm: spectests-llvm emtests-llvm wasitests-llvm cargo test -p wasmer-llvm-backend --release + cargo test -p wasmer-llvm-backend-tests --release cargo test -p wasmer-runtime-core-tests --release --no-default-features --features backend-llvm diff --git a/lib/llvm-backend-tests/Cargo.toml b/lib/llvm-backend-tests/Cargo.toml new file mode 100644 index 00000000000..bb6b24b511c --- /dev/null +++ b/lib/llvm-backend-tests/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "wasmer-llvm-backend-tests" +version = "0.10.2" +authors = ["Nick Lewycky "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +wabt = "0.9.1" +wasmer-runtime-core = { path = "../runtime-core", version = "0.11.0" } +wasmer-runtime = { path = "../runtime", version = "0.11.0" } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.11.0", features = ["test"] } + +[features] diff --git a/lib/llvm-backend-tests/src/lib.rs b/lib/llvm-backend-tests/src/lib.rs new file mode 100644 index 00000000000..ea79b78721e --- /dev/null +++ b/lib/llvm-backend-tests/src/lib.rs @@ -0,0 +1,7 @@ +pub use wabt::wat2wasm; +use wasmer_llvm_backend::LLVMCompiler; +use wasmer_runtime_core::backend::Compiler; + +pub fn get_compiler() -> impl Compiler { + LLVMCompiler::new() +} diff --git a/lib/llvm-backend-tests/tests/compile.rs b/lib/llvm-backend-tests/tests/compile.rs new file mode 100644 index 00000000000..edb59c4692f --- /dev/null +++ b/lib/llvm-backend-tests/tests/compile.rs @@ -0,0 +1,22 @@ +use wasmer_llvm_backend_tests::{get_compiler, wat2wasm}; +use wasmer_runtime::imports; +use wasmer_runtime_core::compile_with; + +#[test] +fn crash_return_with_float_on_stack() { + const MODULE: &str = r#" +(module + (type (;0;) (func)) + (type (;1;) (func (param f64) (result f64))) + (func $_start (type 0)) + (func $fmod (type 1) (param f64) (result f64) + local.get 0 + f64.const 0x0p+0 (;=0;) + f64.mul + return) +) +"#; + 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(); +} From 681219b06c140e7fe2fbd49f91754293a855c85f Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 22 Nov 2019 16:47:02 -0800 Subject: [PATCH 258/342] Fix bug in LLVM lowering of 'return' when the stack has a float on it. --- lib/llvm-backend/src/code.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 63efc3148f7..2bf615e7d5e 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -1412,14 +1412,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } } Operator::Return => { - let frame = state.outermost_frame()?; let current_block = builder.get_insert_block().ok_or(BinaryReaderError { message: "not currently in a block", offset: -1isize as usize, })?; - builder.build_unconditional_branch(frame.br_dest()); - let frame = state.outermost_frame()?; for phi in frame.phis().to_vec().iter() { let (arg, info) = state.pop1_extra()?; @@ -1427,6 +1424,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { phi.add_incoming(&[(&arg, ¤t_block)]); } + let frame = state.outermost_frame()?; + builder.build_unconditional_branch(frame.br_dest()); + state.reachable = false; } From 3ef9f769df6f14f3ac07fb66b3c960c1de5ae8a2 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 22 Nov 2019 17:02:20 -0800 Subject: [PATCH 259/342] Fix TBAA crash with LLVM + the gas middleware. --- lib/llvm-backend/src/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index 717ed043d70..2e3466e45ca 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -1132,7 +1132,7 @@ impl<'a> CtxType<'a> { module.clone(), intrinsics, "context_field_ptr_to_internals", - local_internals_ptr_ptr.as_instruction_value().unwrap(), + local_internals_ptr.as_instruction_value().unwrap(), None, ); unsafe { From 91671d53474c7220c6fdb3a6745e353b731fe2df Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 22 Nov 2019 17:16:25 -0800 Subject: [PATCH 260/342] Add changelog entry. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e99bc60d32..5df0b8ae3ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## **[Unreleased]** +- [#1009](https://github.com/wasmerio/wasmer/pull/1009) Enable LLVM verifier for all tests, add new llvm-backend-tests crate. + ## 0.11.0 - 2019-11-22 - [#713](https://github.com/wasmerio/wasmer/pull/713) Add AArch64 support for singlepass. From 9c0b6a01b2667246dce280be0f2ae17bd54f24c5 Mon Sep 17 00:00:00 2001 From: Syrus Date: Fri, 22 Nov 2019 18:59:40 -0800 Subject: [PATCH 261/342] Fixed Azure pipelines releases --- azure-pipelines.yml | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 77337a3241c..2409dadda9d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -104,7 +104,11 @@ jobs: # RUSTFLAGS: -Ctarget-feature=+crt-static pool: vmImage: $(imageName) - condition: or(in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying'), startsWith(variables['Build.SourceBranch'], 'refs/tags')) + condition: | + or( + in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying'), + startsWith(variables['Build.SourceBranch'], 'refs/tags') + ) steps: - checkout: self submodules: true @@ -126,7 +130,7 @@ jobs: make wapm displayName: Build WAPM condition: | - eq(variables['Build.SourceBranch'], 'refs/heads/master') + startsWith(variables['Build.SourceBranch'], 'refs/tags') - bash: | make build-install cp ./wasmer.tar.gz ./artifacts/$(./scripts/binary-name.sh) @@ -134,7 +138,7 @@ jobs: condition: | and( succeeded(), - eq(variables['Build.SourceBranch'], 'refs/heads/master'), + startsWith(variables['Build.SourceBranch'], 'refs/tags'), not(eq(variables['Agent.OS'], 'Windows_NT')) ) - bash: | @@ -145,7 +149,7 @@ jobs: condition: | and( succeeded(), - eq(variables['Build.SourceBranch'], 'refs/heads/master'), + startsWith(variables['Build.SourceBranch'], 'refs/tags'), eq(variables['Agent.OS'], 'Windows_NT') ) - publish: $(System.DefaultWorkingDirectory)/artifacts @@ -167,7 +171,11 @@ jobs: # RUSTFLAGS: -Ctarget-feature=+crt-static pool: vmImage: $(imageName) - condition: or(in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying'), startsWith(variables['Build.SourceBranch'], 'refs/tags')) + condition: | + or( + in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying'), + startsWith(variables['Build.SourceBranch'], 'refs/tags') + ) steps: - checkout: self submodules: true @@ -205,7 +213,8 @@ jobs: dependsOn: - Build_CLI - Build_Library - condition: or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), startsWith(variables['Build.SourceBranch'], 'refs/tags')) + condition: | + startsWith(variables['Build.SourceBranch'], 'refs/tags') steps: # - download: current - task: DownloadPipelineArtifact@1 @@ -220,7 +229,7 @@ jobs: displayName: Set the tag name as an environment variable - task: GithubRelease@0 displayName: "Create GitHub Release" - condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master')) + condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags')) inputs: gitHubConnection: 'wasmer' repositoryName: 'wasmerio/wasmer' From 7ca0430a40f803a3665f6ce6b69fb06f2a859021 Mon Sep 17 00:00:00 2001 From: Patrick Ventuzelo Date: Mon, 25 Nov 2019 13:17:07 +0100 Subject: [PATCH 262/342] activate pre_validation when llvm backend selected --- lib/runtime-core/src/codegen.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index 99158fb1501..7b4533296b9 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -263,7 +263,7 @@ impl< fn requires_pre_validation(backend: Backend) -> bool { match backend { Backend::Cranelift => true, - Backend::LLVM => false, + Backend::LLVM => true, Backend::Singlepass => false, } } From 95ccd998092e333f8c8292ac087dfc5c6589a68d Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Mon, 25 Nov 2019 11:25:05 -0800 Subject: [PATCH 263/342] Added ARM reference --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f513663f5f1..6b8ca9d48bf 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ ## Introduction -[Wasmer](https://wasmer.io/) is a standalone WebAssembly runtime for running WebAssembly [outside of the browser](https://webassembly.org/docs/non-web/), supporting [WASI](https://github.com/WebAssembly/WASI) and [Emscripten](https://emscripten.org/). +[Wasmer](https://wasmer.io/) is a standalone WebAssembly runtime for running WebAssembly [outside of the browser](https://webassembly.org/docs/non-web/), supporting [WASI](https://github.com/WebAssembly/WASI) and [Emscripten](https://emscripten.org/). Wasmer can be used standalone (via the CLI) and embedded in different languages, running in x86 and [ARM devices](https://medium.com/wasmer/running-webassembly-on-arm-7d365ed0e50c). Install the Wasmer CLI with: From 4e2440daec173e3fd6d24f8f5d14150a9e8e19cf Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 25 Nov 2019 14:46:16 -0800 Subject: [PATCH 264/342] Add a 'clear' method to map. --- lib/runtime-core/src/structures/map.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/runtime-core/src/structures/map.rs b/lib/runtime-core/src/structures/map.rs index b3f20b5cb44..08773b50a4b 100644 --- a/lib/runtime-core/src/structures/map.rs +++ b/lib/runtime-core/src/structures/map.rs @@ -37,6 +37,11 @@ where } } + /// Clears the map. Keeps the allocated memory for future use. + pub fn clear(&mut self) { + self.elems.clear(); + } + /// Returns the size of this map. pub fn len(&self) -> usize { self.elems.len() From 49665d57975e47f449a526292333ee6647ea1ffa Mon Sep 17 00:00:00 2001 From: Patrick Ventuzelo Date: Tue, 26 Nov 2019 09:17:13 +0100 Subject: [PATCH 265/342] use checked_sub for peekn_extra --- lib/llvm-backend/src/state.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/llvm-backend/src/state.rs b/lib/llvm-backend/src/state.rs index 5f70bb3c580..fde5eb52e40 100644 --- a/lib/llvm-backend/src/state.rs +++ b/lib/llvm-backend/src/state.rs @@ -240,14 +240,11 @@ impl State { &self, n: usize, ) -> Result<&[(BasicValueEnum, ExtraInfo)], BinaryReaderError> { - if self.stack.len() < n { - return Err(BinaryReaderError { - message: "invalid value stack", - offset: -1isize as usize, - }); - } + let new_len = self.stack.len().checked_sub(n).ok_or(BinaryReaderError { + message: "invalid value stack", + offset: -1isize as usize, + })?; - let new_len = self.stack.len() - n; Ok(&self.stack[new_len..]) } From fafc7ad38c08bf8dd65f59ffe64ae76efe021c61 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Wed, 6 Nov 2019 13:40:51 -0800 Subject: [PATCH 266/342] Add "known to not contain non-arithmetic NaNs" to ExtraInfo in LLVM backend. Not wired up yet. --- lib/llvm-backend/src/code.rs | 118 ++++++++++++++++------------------ lib/llvm-backend/src/state.rs | 72 ++++++++++++++++++--- 2 files changed, 120 insertions(+), 70 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index b4f113a2f1b..874033eef85 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -388,16 +388,14 @@ fn v128_into_int_vec( 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) - } + let value = if info.has_pending_f32_nan() { + let value = builder.build_bitcast(value, intrinsics.f32x4_ty, ""); + canonicalize_nans(builder, intrinsics, value) + } else if info.has_pending_f64_nan() { + let value = builder.build_bitcast(value, intrinsics.f64x2_ty, ""); + canonicalize_nans(builder, intrinsics, value) + } else { + value }; builder .build_bitcast(value, int_vec_ty, "") @@ -448,7 +446,7 @@ fn v128_into_f32x4( value: BasicValueEnum, info: ExtraInfo, ) -> VectorValue { - let value = if info == ExtraInfo::PendingF64NaN { + let value = if info.has_pending_f64_nan() { let value = builder.build_bitcast(value, intrinsics.f64x2_ty, ""); canonicalize_nans(builder, intrinsics, value) } else { @@ -467,7 +465,7 @@ fn v128_into_f64x2( value: BasicValueEnum, info: ExtraInfo, ) -> VectorValue { - let value = if info == ExtraInfo::PendingF32NaN { + let value = if info.has_pending_f32_nan() { let value = builder.build_bitcast(value, intrinsics.f32x4_ty, ""); canonicalize_nans(builder, intrinsics, value) } else { @@ -484,32 +482,30 @@ fn apply_pending_canonicalization( 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) - } + if info.has_pending_f32_nan() { + 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) - } + } else if info.has_pending_f64_nan() { + 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) } + } else { + value } } @@ -2747,13 +2743,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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::PendingF32NaN); + state.push1_extra(res, ExtraInfo::pending_f32_nan()); } 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); + state.push1_extra(res, ExtraInfo::pending_f64_nan()); } Operator::F32x4Add => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -2761,7 +2757,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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_extra(res, ExtraInfo::PendingF32NaN); + state.push1_extra(res, ExtraInfo::pending_f32_nan()); } Operator::F64x2Add => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -2769,19 +2765,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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_extra(res, ExtraInfo::PendingF64NaN); + state.push1_extra(res, ExtraInfo::pending_f64_nan()); } Operator::F32Sub => { 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::PendingF32NaN); + state.push1_extra(res, ExtraInfo::pending_f32_nan()); } 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); + state.push1_extra(res, ExtraInfo::pending_f64_nan()); } Operator::F32x4Sub => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -2789,7 +2785,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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_extra(res, ExtraInfo::PendingF32NaN); + state.push1_extra(res, ExtraInfo::pending_f32_nan()); } Operator::F64x2Sub => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -2797,19 +2793,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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_extra(res, ExtraInfo::PendingF64NaN); + state.push1_extra(res, ExtraInfo::pending_f64_nan()); } Operator::F32Mul => { 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::PendingF32NaN); + state.push1_extra(res, ExtraInfo::pending_f32_nan()); } 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); + state.push1_extra(res, ExtraInfo::pending_f64_nan()); } Operator::F32x4Mul => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -2817,7 +2813,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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_extra(res, ExtraInfo::PendingF32NaN); + state.push1_extra(res, ExtraInfo::pending_f32_nan()); } Operator::F64x2Mul => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -2825,19 +2821,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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_extra(res, ExtraInfo::PendingF64NaN); + state.push1_extra(res, ExtraInfo::pending_f64_nan()); } Operator::F32Div => { 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::PendingF32NaN); + state.push1_extra(res, ExtraInfo::pending_f32_nan()); } 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); + state.push1_extra(res, ExtraInfo::pending_f64_nan()); } Operator::F32x4Div => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -2845,7 +2841,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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_extra(res, ExtraInfo::PendingF32NaN); + state.push1_extra(res, ExtraInfo::pending_f32_nan()); } Operator::F64x2Div => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -2853,7 +2849,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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_extra(res, ExtraInfo::PendingF64NaN); + state.push1_extra(res, ExtraInfo::pending_f64_nan()); } Operator::F32Sqrt => { let input = state.pop1()?; @@ -2862,7 +2858,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1_extra(res, ExtraInfo::PendingF32NaN); + state.push1_extra(res, ExtraInfo::pending_f32_nan()); } Operator::F64Sqrt => { let input = state.pop1()?; @@ -2871,7 +2867,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1_extra(res, ExtraInfo::PendingF64NaN); + state.push1_extra(res, ExtraInfo::pending_f64_nan()); } Operator::F32x4Sqrt => { let (v, i) = state.pop1_extra()?; @@ -2886,7 +2882,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .left() .unwrap(); let bits = builder.build_bitcast(res, intrinsics.i128_ty, "bits"); - state.push1_extra(bits, ExtraInfo::PendingF32NaN); + state.push1_extra(bits, ExtraInfo::pending_f32_nan()); } Operator::F64x2Sqrt => { let (v, i) = state.pop1_extra()?; @@ -3386,7 +3382,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1_extra(res, ExtraInfo::PendingF32NaN); + state.push1_extra(res, ExtraInfo::pending_f32_nan()); } Operator::F64Ceil => { let input = state.pop1()?; @@ -3395,7 +3391,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1_extra(res, ExtraInfo::PendingF64NaN); + state.push1_extra(res, ExtraInfo::pending_f64_nan()); } Operator::F32Floor => { let input = state.pop1()?; @@ -3404,7 +3400,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1_extra(res, ExtraInfo::PendingF32NaN); + state.push1_extra(res, ExtraInfo::pending_f32_nan()); } Operator::F64Floor => { let input = state.pop1()?; @@ -3413,7 +3409,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1_extra(res, ExtraInfo::PendingF64NaN); + state.push1_extra(res, ExtraInfo::pending_f64_nan()); } Operator::F32Trunc => { let (v, i) = state.pop1_extra()?; @@ -4311,13 +4307,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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); + state.push1_extra(res, ExtraInfo::pending_f32_nan()); } Operator::F64PromoteF32 => { 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); + state.push1_extra(res, ExtraInfo::pending_f64_nan()); } Operator::F32ConvertSI32 | Operator::F32ConvertSI64 => { let v1 = state.pop1()?.into_int_value(); diff --git a/lib/llvm-backend/src/state.rs b/lib/llvm-backend/src/state.rs index 0d46dc5c099..c051dde0bd9 100644 --- a/lib/llvm-backend/src/state.rs +++ b/lib/llvm-backend/src/state.rs @@ -4,6 +4,7 @@ use inkwell::{ }; use smallvec::SmallVec; use std::cell::Cell; +use std::ops::Add; use wasmparser::BinaryReaderError; #[derive(Debug)] @@ -68,22 +69,75 @@ 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 +pub struct ExtraInfo { + state: u8, +} +impl ExtraInfo { + // This value 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, + pub fn pending_f32_nan() -> ExtraInfo { + ExtraInfo { state: 1 } + } - // This values is required to be arithmetic 64-bit NaN (or 64x2) by the WAsm + // This value 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, + pub fn pending_f64_nan() -> ExtraInfo { + ExtraInfo { state: 2 } + } + + // This value either does not contain a 32-bit NaN, or it contains an + // arithmetic NaN. In SIMD, applies to all 4 lanes. + pub fn arithmetic_f32() -> ExtraInfo { + ExtraInfo { state: 4 } + } + + // This value either does not contain a 64-bit NaN, or it contains an + // arithmetic NaN. In SIMD, applies to both lanes. + pub fn arithmetic_f64() -> ExtraInfo { + ExtraInfo { state: 8 } + } + + pub fn has_pending_f32_nan(&self) -> bool { + self.state & ExtraInfo::pending_f32_nan().state != 0 + } + pub fn has_pending_f64_nan(&self) -> bool { + self.state & ExtraInfo::pending_f64_nan().state != 0 + } + pub fn is_arithmetic_f32(&self) -> bool { + self.state & ExtraInfo::arithmetic_f32().state != 0 + } + pub fn is_arithmetic_f64(&self) -> bool { + self.state & ExtraInfo::arithmetic_f64().state != 0 + } } impl Default for ExtraInfo { fn default() -> Self { - ExtraInfo::None + ExtraInfo { state: 0 } + } +} +impl Add for ExtraInfo { + type Output = Self; + + fn add(self, other: Self) -> Self { + assert!(self.has_pending_f32_nan() && other.has_pending_f64_nan()); + assert!(self.has_pending_f64_nan() && other.has_pending_f32_nan()); + ExtraInfo { + state: if self.is_arithmetic_f32() || other.is_arithmetic_f32() { + ExtraInfo::arithmetic_f32().state + } else if self.has_pending_f32_nan() || other.has_pending_f32_nan() { + ExtraInfo::pending_f32_nan().state + } else { + 0 + } + if self.is_arithmetic_f64() || other.is_arithmetic_f64() { + ExtraInfo::arithmetic_f64().state + } else if self.has_pending_f64_nan() || other.has_pending_f64_nan() { + ExtraInfo::pending_f64_nan().state + } else { + 0 + }, + } } } @@ -165,7 +219,7 @@ impl State { } pub fn push1(&mut self, value: T) { - self.push1_extra(value, ExtraInfo::None); + self.push1_extra(value, Default::default()); } pub fn push1_extra(&mut self, value: T, info: ExtraInfo) { From 26c8fd52c8d5456479fc81114a56c8cbf2c71229 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Wed, 6 Nov 2019 17:14:32 -0800 Subject: [PATCH 267/342] Initial implementation of "known to be arithmetic NaN / not NaN". --- lib/llvm-backend/src/code.rs | 430 ++++++++++++++++++++++------------ lib/llvm-backend/src/state.rs | 50 ++-- 2 files changed, 319 insertions(+), 161 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 874033eef85..5b8d078cc68 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -1484,21 +1484,41 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { // Generate const values. Operator::I32Const { value } => { let i = intrinsics.i32_ty.const_int(value as u64, false); - state.push1(i); + let info = if is_f32_arithmetic(value as u32) { + ExtraInfo::arithmetic_f32() + } else { + Default::default() + }; + state.push1_extra(i, info); } Operator::I64Const { value } => { let i = intrinsics.i64_ty.const_int(value as u64, false); - state.push1(i); + let info = if is_f64_arithmetic(value as u64) { + ExtraInfo::arithmetic_f64() + } else { + Default::default() + }; + state.push1_extra(i, info); } Operator::F32Const { value } => { let bits = intrinsics.i32_ty.const_int(value.bits() as u64, false); + let info = if is_f32_arithmetic(value.bits()) { + ExtraInfo::arithmetic_f32() + } else { + Default::default() + }; let f = builder.build_bitcast(bits, intrinsics.f32_ty, "f"); - state.push1(f); + state.push1_extra(f, info); } Operator::F64Const { value } => { let bits = intrinsics.i64_ty.const_int(value.bits(), false); + let info = if is_f64_arithmetic(value.bits()) { + ExtraInfo::arithmetic_f64() + } else { + Default::default() + }; let f = builder.build_bitcast(bits, intrinsics.f64_ty, "f"); - state.push1(f); + state.push1_extra(f, info); } Operator::V128Const { value } => { let mut hi: [u8; 8] = Default::default(); @@ -1507,11 +1527,31 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { lo.copy_from_slice(&value.bytes()[8..16]); let packed = [u64::from_le_bytes(hi), u64::from_le_bytes(lo)]; let i = intrinsics.i128_ty.const_int_arbitrary_precision(&packed); - state.push1(i); + let mut quad1: [u8; 4] = Default::default(); + let mut quad2: [u8; 4] = Default::default(); + let mut quad3: [u8; 4] = Default::default(); + let mut quad4: [u8; 4] = Default::default(); + quad1.copy_from_slice(&value.bytes()[0..4]); + quad2.copy_from_slice(&value.bytes()[4..8]); + quad3.copy_from_slice(&value.bytes()[8..12]); + quad4.copy_from_slice(&value.bytes()[12..16]); + let mut info: ExtraInfo = Default::default(); + if is_f32_arithmetic(u32::from_le_bytes(quad1)) + && is_f32_arithmetic(u32::from_le_bytes(quad2)) + && is_f32_arithmetic(u32::from_le_bytes(quad3)) + && is_f32_arithmetic(u32::from_le_bytes(quad4)) + { + info |= ExtraInfo::arithmetic_f32(); + } + if is_f64_arithmetic(packed[0]) && is_f64_arithmetic(packed[1]) { + info |= ExtraInfo::arithmetic_f64(); + } + state.push1_extra(i, info); } Operator::I8x16Splat => { - let v = state.pop1()?.into_int_value(); + let (v, i) = state.pop1_extra()?; + let v = v.into_int_value(); let v = builder.build_int_truncate(v, intrinsics.i8_ty, ""); let res = splat_vector( builder, @@ -1521,10 +1561,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { &state.var_name(), ); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, i); } Operator::I16x8Splat => { - let v = state.pop1()?.into_int_value(); + let (v, i) = state.pop1_extra()?; + let v = v.into_int_value(); let v = builder.build_int_truncate(v, intrinsics.i16_ty, ""); let res = splat_vector( builder, @@ -1534,10 +1575,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { &state.var_name(), ); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, i); } Operator::I32x4Splat => { - let v = state.pop1()?; + let (v, i) = state.pop1_extra()?; let res = splat_vector( builder, intrinsics, @@ -1546,10 +1587,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { &state.var_name(), ); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, i); } Operator::I64x2Splat => { - let v = state.pop1()?; + let (v, i) = state.pop1_extra()?; let res = splat_vector( builder, intrinsics, @@ -1558,7 +1599,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { &state.var_name(), ); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, i); } Operator::F32x4Splat => { let (v, i) = state.pop1_extra()?; @@ -1674,7 +1715,20 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::Select => { - let (v1, v2, cond) = state.pop3()?; + let ((v1, i1), (v2, i2), (cond, _)) = state.pop3_extra()?; + // We don't bother canonicalizing 'cond' here because we only + // compare it to zero, and that's invariant under + // canonicalization. + let (v1, v2) = if i1.has_pending_f32_nan() != i1.has_pending_f32_nan() + || i1.has_pending_f64_nan() != i2.has_pending_f64_nan() + { + ( + apply_pending_canonicalization(builder, intrinsics, v1, i1), + apply_pending_canonicalization(builder, intrinsics, v2, i2), + ) + } else { + (v1, v2) + }; let cond_value = builder.build_int_compare( IntPredicate::NE, cond.into_int_value(), @@ -1682,7 +1736,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { &state.var_name(), ); let res = builder.build_select(cond_value, v1, v2, &state.var_name()); - state.push1(res); + let info = { + let mut info = i1 & i2; + if i1.has_pending_f32_nan() { + assert!(i2.has_pending_f32_nan()); + info |= ExtraInfo::pending_f32_nan(); + } + if i1.has_pending_f64_nan() { + assert!(i2.has_pending_f64_nan()); + info |= ExtraInfo::pending_f64_nan(); + } + info + }; + state.push1_extra(res, info); } Operator::Call { function_index } => { let func_index = FuncIndex::new(function_index as usize); @@ -2650,7 +2716,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, ExtraInfo::arithmetic_f32()); } Operator::I64Clz => { let input = state.pop1()?; @@ -2664,7 +2730,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, ExtraInfo::arithmetic_f64()); } Operator::I32Ctz => { let input = state.pop1()?; @@ -2678,7 +2744,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, ExtraInfo::arithmetic_f32()); } Operator::I64Ctz => { let input = state.pop1()?; @@ -2692,7 +2758,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, ExtraInfo::arithmetic_f64()); } Operator::I32Popcnt => { let input = state.pop1()?; @@ -2701,7 +2767,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, ExtraInfo::arithmetic_f32()); } Operator::I64Popcnt => { let input = state.pop1()?; @@ -2710,7 +2776,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, ExtraInfo::arithmetic_f64()); } Operator::I32Eqz => { let input = state.pop1()?.into_int_value(); @@ -2721,7 +2787,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { &state.var_name(), ); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); + state.push1_extra(res, ExtraInfo::arithmetic_f32()); } Operator::I64Eqz => { let input = state.pop1()?.into_int_value(); @@ -2732,7 +2798,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { &state.var_name(), ); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); + state.push1_extra(res, ExtraInfo::arithmetic_f64()); } /*************************** @@ -2740,16 +2806,16 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#floating-point-arithmetic-instructions ***************************/ Operator::F32Add => { - let (v1, v2) = state.pop2()?; + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; 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::pending_f32_nan()); + state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f32_nan()); } Operator::F64Add => { - let (v1, v2) = state.pop2()?; + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; 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::pending_f64_nan()); + state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f64_nan()); } Operator::F32x4Add => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -2757,7 +2823,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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_extra(res, ExtraInfo::pending_f32_nan()); + state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f32_nan()); } Operator::F64x2Add => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -2765,19 +2831,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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_extra(res, ExtraInfo::pending_f64_nan()); + state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f64_nan()); } Operator::F32Sub => { - let (v1, v2) = state.pop2()?; + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; 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::pending_f32_nan()); + state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f32_nan()); } Operator::F64Sub => { - let (v1, v2) = state.pop2()?; + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; 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::pending_f64_nan()); + state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f64_nan()); } Operator::F32x4Sub => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -2785,7 +2851,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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_extra(res, ExtraInfo::pending_f32_nan()); + state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f32_nan()); } Operator::F64x2Sub => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -2793,19 +2859,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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_extra(res, ExtraInfo::pending_f64_nan()); + state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f64_nan()); } Operator::F32Mul => { - let (v1, v2) = state.pop2()?; + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; 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::pending_f32_nan()); + state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f32_nan()); } Operator::F64Mul => { - let (v1, v2) = state.pop2()?; + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; 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::pending_f64_nan()); + state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f64_nan()); } Operator::F32x4Mul => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -2813,7 +2879,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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_extra(res, ExtraInfo::pending_f32_nan()); + state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f32_nan()); } Operator::F64x2Mul => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -2821,7 +2887,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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_extra(res, ExtraInfo::pending_f64_nan()); + state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f64_nan()); } Operator::F32Div => { let (v1, v2) = state.pop2()?; @@ -2951,7 +3017,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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); + state.push1_extra(res, ExtraInfo::arithmetic_f32()); } Operator::F64Min => { // This implements the same logic as LLVM's @llvm.minimum @@ -3005,7 +3071,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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); + state.push1_extra(res, ExtraInfo::arithmetic_f64()); } Operator::F32x4Min => { // This implements the same logic as LLVM's @llvm.minimum @@ -3071,7 +3137,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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); + state.push1_extra(res, ExtraInfo::arithmetic_f32()); } Operator::F64x2Min => { // This implements the same logic as LLVM's @llvm.minimum @@ -3137,7 +3203,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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); + state.push1_extra(res, ExtraInfo::arithmetic_f64()); } Operator::F32Max => { // This implements the same logic as LLVM's @llvm.maximum @@ -3190,7 +3256,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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); + state.push1_extra(res, ExtraInfo::arithmetic_f32()); } Operator::F64Max => { // This implements the same logic as LLVM's @llvm.maximum @@ -3243,7 +3309,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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); + state.push1_extra(res, ExtraInfo::arithmetic_f64()); } Operator::F32x4Max => { // This implements the same logic as LLVM's @llvm.maximum @@ -3308,7 +3374,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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); + state.push1_extra(res, ExtraInfo::arithmetic_f32()); } Operator::F64x2Max => { // This implements the same logic as LLVM's @llvm.maximum @@ -3373,43 +3439,43 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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); + state.push1_extra(res, ExtraInfo::arithmetic_f64()); } Operator::F32Ceil => { - let input = state.pop1()?; + let (input, info) = state.pop1_extra()?; let res = builder .build_call(intrinsics.ceil_f32, &[input], &state.var_name()) .try_as_basic_value() .left() .unwrap(); - state.push1_extra(res, ExtraInfo::pending_f32_nan()); + state.push1_extra(res, info | ExtraInfo::pending_f32_nan()); } Operator::F64Ceil => { - let input = state.pop1()?; + let (input, info) = state.pop1_extra()?; let res = builder .build_call(intrinsics.ceil_f64, &[input], &state.var_name()) .try_as_basic_value() .left() .unwrap(); - state.push1_extra(res, ExtraInfo::pending_f64_nan()); + state.push1_extra(res, info | ExtraInfo::pending_f64_nan()); } Operator::F32Floor => { - let input = state.pop1()?; + let (input, info) = state.pop1_extra()?; let res = builder .build_call(intrinsics.floor_f32, &[input], &state.var_name()) .try_as_basic_value() .left() .unwrap(); - state.push1_extra(res, ExtraInfo::pending_f32_nan()); + state.push1_extra(res, info | ExtraInfo::pending_f32_nan()); } Operator::F64Floor => { - let input = state.pop1()?; + let (input, info) = state.pop1_extra()?; let res = builder .build_call(intrinsics.floor_f64, &[input], &state.var_name()) .try_as_basic_value() .left() .unwrap(); - state.push1_extra(res, ExtraInfo::pending_f64_nan()); + state.push1_extra(res, info | ExtraInfo::pending_f64_nan()); } Operator::F32Trunc => { let (v, i) = state.pop1_extra()?; @@ -3477,7 +3543,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .unwrap(); // The exact NaN returned by F32Abs is fully defined. Do not // adjust. - state.push1(res); + state.push1_extra(res, i.strip_pending()); } Operator::F64Abs => { let (v, i) = state.pop1_extra()?; @@ -3493,7 +3559,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .unwrap(); // The exact NaN returned by F64Abs is fully defined. Do not // adjust. - state.push1(res); + state.push1_extra(res, i.strip_pending()); } Operator::F32x4Abs => { let (v, i) = state.pop1_extra()?; @@ -3511,7 +3577,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); // The exact NaN returned by F32x4Abs is fully defined. Do not // adjust. - state.push1(res); + state.push1_extra(res, i.strip_pending()); } Operator::F64x2Abs => { let (v, i) = state.pop1_extra()?; @@ -3525,7 +3591,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); // The exact NaN returned by F32x4Abs is fully defined. Do not // adjust. - state.push1(res); + state.push1_extra(res, i.strip_pending()); } Operator::F32x4Neg => { let (v, i) = state.pop1_extra()?; @@ -3536,7 +3602,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); // The exact NaN returned by F32x4Neg is fully defined. Do not // adjust. - state.push1(res); + state.push1_extra(res, i.strip_pending()); } Operator::F64x2Neg => { let (v, i) = state.pop1_extra()?; @@ -3547,7 +3613,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); // The exact NaN returned by F64x2Neg is fully defined. Do not // adjust. - state.push1(res); + state.push1_extra(res, i.strip_pending()); } Operator::F32Neg | Operator::F64Neg => { let (v, i) = state.pop1_extra()?; @@ -3556,7 +3622,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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); + state.push1_extra(res, i.strip_pending()); } Operator::F32Copysign => { let ((mag, mag_info), (sgn, sgn_info)) = state.pop2_extra()?; @@ -3569,7 +3635,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .unwrap(); // The exact NaN returned by F32Copysign is fully defined. // Do not adjust. - state.push1(res); + state.push1_extra(res, mag_info.strip_pending()); } Operator::F64Copysign => { let ((mag, mag_info), (sgn, sgn_info)) = state.pop2_extra()?; @@ -3582,7 +3648,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .unwrap(); // The exact NaN returned by F32Copysign is fully defined. // Do not adjust. - state.push1(res); + state.push1_extra(res, mag_info.strip_pending()); } /*************************** @@ -3594,7 +3660,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let cond = builder.build_int_compare(IntPredicate::EQ, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); + state.push1_extra( + res, + ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), + ); } Operator::I8x16Eq => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -3628,7 +3697,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let cond = builder.build_int_compare(IntPredicate::NE, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); + state.push1_extra( + res, + ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), + ); } Operator::I8x16Ne => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -3662,7 +3734,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let cond = builder.build_int_compare(IntPredicate::SLT, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); + state.push1_extra( + res, + ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), + ); } Operator::I8x16LtS => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -3730,7 +3805,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let cond = builder.build_int_compare(IntPredicate::SLE, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); + state.push1_extra( + res, + ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), + ); } Operator::I8x16LeS => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -3764,7 +3842,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let cond = builder.build_int_compare(IntPredicate::ULE, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); + state.push1_extra( + res, + ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), + ); } Operator::I8x16LeU => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -3798,7 +3879,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let cond = builder.build_int_compare(IntPredicate::SGT, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); + state.push1_extra( + res, + ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), + ); } Operator::I8x16GtS => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -3832,7 +3916,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let cond = builder.build_int_compare(IntPredicate::UGT, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); + state.push1_extra( + res, + ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), + ); } Operator::I8x16GtU => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -3900,7 +3987,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let cond = builder.build_int_compare(IntPredicate::UGE, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); + state.push1_extra( + res, + ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), + ); } Operator::I8x16GeU => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -3940,7 +4030,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let cond = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); + state.push1_extra( + res, + ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), + ); } Operator::F32x4Eq => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -3966,7 +4059,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let cond = builder.build_float_compare(FloatPredicate::UNE, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); + state.push1_extra( + res, + ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), + ); } Operator::F32x4Ne => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -3992,7 +4088,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let cond = builder.build_float_compare(FloatPredicate::OLT, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); + state.push1_extra( + res, + ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), + ); } Operator::F32x4Lt => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -4018,7 +4117,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let cond = builder.build_float_compare(FloatPredicate::OLE, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); + state.push1_extra( + res, + ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), + ); } Operator::F32x4Le => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -4044,7 +4146,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let cond = builder.build_float_compare(FloatPredicate::OGT, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); + state.push1_extra( + res, + ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), + ); } Operator::F32x4Gt => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -4070,7 +4175,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let cond = builder.build_float_compare(FloatPredicate::OGE, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); - state.push1(res); + state.push1_extra( + res, + ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), + ); } Operator::F32x4Ge => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -4108,7 +4216,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Operator::I64ExtendUI32 => { let v1 = state.pop1()?.into_int_value(); let res = builder.build_int_z_extend(v1, intrinsics.i64_ty, &state.var_name()); - state.push1(res); + state.push1_extra(res, ExtraInfo::arithmetic_f64()); } Operator::I32x4TruncSF32x4Sat => { let v = state.pop1()?.into_int_value(); @@ -4383,23 +4491,23 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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); + state.push1_extra(ret, ExtraInfo::arithmetic_f32()); } Operator::I64ReinterpretF64 => { 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); + state.push1_extra(ret, ExtraInfo::arithmetic_f64()); } Operator::F32ReinterpretI32 => { - let v = state.pop1()?; + let (v, i) = state.pop1_extra()?; let ret = builder.build_bitcast(v, intrinsics.f32_ty, &state.var_name()); - state.push1(ret); + state.push1_extra(ret, i); } Operator::F64ReinterpretI64 => { - let v = state.pop1()?; + let (v, i) = state.pop1_extra()?; let ret = builder.build_bitcast(v, intrinsics.f64_ty, &state.var_name()); - state.push1(ret); + state.push1_extra(ret, i); } /*************************** @@ -4880,7 +4988,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i32_ty, &state.var_name(), ); - state.push1(result); + state.push1_extra(result, ExtraInfo::arithmetic_f32()); } Operator::I32Load16U { ref memarg } => { let effective_address = resolve_memory_ptr( @@ -4913,7 +5021,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i32_ty, &state.var_name(), ); - state.push1(result); + state.push1_extra(result, ExtraInfo::arithmetic_f32()); } Operator::I64Load8U { ref memarg } => { let effective_address = resolve_memory_ptr( @@ -4946,7 +5054,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i64_ty, &state.var_name(), ); - state.push1(result); + state.push1_extra(result, ExtraInfo::arithmetic_f64()); } Operator::I64Load16U { ref memarg } => { let effective_address = resolve_memory_ptr( @@ -4979,7 +5087,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i64_ty, &state.var_name(), ); - state.push1(result); + state.push1_extra(result, ExtraInfo::arithmetic_f64()); } Operator::I64Load32U { ref memarg } => { let effective_address = resolve_memory_ptr( @@ -5012,7 +5120,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i64_ty, &state.var_name(), ); - state.push1(result); + state.push1_extra(result, ExtraInfo::arithmetic_f64()); } Operator::I32Store8 { ref memarg } | Operator::I64Store8 { ref memarg } => { @@ -5122,7 +5230,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { &state.var_name(), ); let res = builder.build_int_z_extend(res, intrinsics.i32_ty, ""); - state.push1(res); + state.push1_extra( + res, + ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), + ); } Operator::I8x16AllTrue | Operator::I16x8AllTrue @@ -5151,7 +5262,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { &state.var_name(), ); let res = builder.build_int_z_extend(res, intrinsics.i32_ty, ""); - state.push1(res); + state.push1_extra( + res, + ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), + ); } Operator::I8x16ExtractLaneS { lane } => { let (v, i) = state.pop1_extra()?; @@ -5171,7 +5285,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .build_extract_element(v, idx, &state.var_name()) .into_int_value(); let res = builder.build_int_z_extend(res, intrinsics.i32_ty, ""); - state.push1(res); + state.push1_extra(res, ExtraInfo::arithmetic_f32()); } Operator::I16x8ExtractLaneS { lane } => { let (v, i) = state.pop1_extra()?; @@ -5191,35 +5305,45 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .build_extract_element(v, idx, &state.var_name()) .into_int_value(); let res = builder.build_int_z_extend(res, intrinsics.i32_ty, ""); - state.push1(res); + state.push1_extra(res, ExtraInfo::arithmetic_f32()); } Operator::I32x4ExtractLane { lane } => { 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); + state.push1_extra(res, i.strip_pending()); } Operator::I64x2ExtractLane { lane } => { 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); + state.push1_extra(res, i.strip_pending()); } Operator::F32x4ExtractLane { lane } => { 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); + let i = if i.has_pending_f64_nan() { + i.strip_pending() + } else { + i + }; + state.push1_extra(res, i); } Operator::F64x2ExtractLane { lane } => { 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); + let i = if i.has_pending_f32_nan() { + i.strip_pending() + } else { + i + }; + state.push1_extra(res, i); } Operator::I8x16ReplaceLane { lane } => { let ((v1, i1), (v2, _)) = state.pop2_extra()?; @@ -5242,22 +5366,22 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32x4ReplaceLane { lane } => { - let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let ((v1, i1), (v2, i2)) = 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()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, i1 & i2 & ExtraInfo::arithmetic_f32()); } Operator::I64x2ReplaceLane { lane } => { - let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let ((v1, i1), (v2, i2)) = 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()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, i1 & i2 & ExtraInfo::arithmetic_f64()); } Operator::F32x4ReplaceLane { lane } => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -5267,7 +5391,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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); + state.push1_extra(res, i1 & i2 & ExtraInfo::arithmetic_f32()); } Operator::F64x2ReplaceLane { lane } => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -5277,7 +5401,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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); + state.push1_extra(res, i1 & i2 & ExtraInfo::arithmetic_f64()); } Operator::V8x16Swizzle => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; @@ -5601,7 +5725,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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); + state.push1_extra(result, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicLoad16U { ref memarg } => { let effective_address = resolve_memory_ptr( @@ -5634,7 +5758,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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); + state.push1_extra(result, ExtraInfo::arithmetic_f32()); } Operator::I64AtomicLoad8U { ref memarg } => { let effective_address = resolve_memory_ptr( @@ -5667,7 +5791,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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); + state.push1_extra(result, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicLoad16U { ref memarg } => { let effective_address = resolve_memory_ptr( @@ -5700,7 +5824,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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); + state.push1_extra(result, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicLoad32U { ref memarg } => { let effective_address = resolve_memory_ptr( @@ -5733,7 +5857,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 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); + state.push1_extra(result, ExtraInfo::arithmetic_f64()); } Operator::I32AtomicStore { ref memarg } => { let value = state.pop1()?; @@ -5927,7 +6051,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmw16UAdd { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -5969,7 +6093,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmwAdd { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6050,7 +6174,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw16UAdd { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6092,7 +6216,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw32UAdd { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6134,7 +6258,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmwAdd { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6215,7 +6339,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmw16USub { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6257,7 +6381,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmwSub { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6338,7 +6462,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I64AtomicRmw16USub { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6380,7 +6504,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw32USub { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6422,7 +6546,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmwSub { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6503,7 +6627,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmw16UAnd { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6545,7 +6669,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmwAnd { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6626,7 +6750,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw16UAnd { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6668,7 +6792,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw32UAnd { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6710,7 +6834,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmwAnd { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6791,7 +6915,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmw16UOr { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6833,7 +6957,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmwOr { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6873,7 +6997,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I64AtomicRmw8UOr { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6915,7 +7039,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw16UOr { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6957,7 +7081,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw32UOr { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6999,7 +7123,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmwOr { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -7080,7 +7204,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmw16UXor { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -7122,7 +7246,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmwXor { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -7203,7 +7327,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw16UXor { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -7245,7 +7369,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw32UXor { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -7287,7 +7411,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmwXor { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -7368,7 +7492,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmw16UXchg { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -7410,7 +7534,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmwXchg { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -7491,7 +7615,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw16UXchg { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -7533,7 +7657,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw32UXchg { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -7575,7 +7699,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Some(0), ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmwXchg { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -7664,7 +7788,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .unwrap() .into_int_value(); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmw16UCmpxchg { ref memarg } => { let (cmp, new) = state.pop2()?; @@ -7714,7 +7838,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .unwrap() .into_int_value(); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmwCmpxchg { ref memarg } => { let (cmp, new) = state.pop2()?; @@ -7806,7 +7930,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .unwrap() .into_int_value(); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw16UCmpxchg { ref memarg } => { let (cmp, new) = state.pop2()?; @@ -7856,7 +7980,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .unwrap() .into_int_value(); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw32UCmpxchg { ref memarg } => { let (cmp, new) = state.pop2()?; @@ -7906,7 +8030,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .unwrap() .into_int_value(); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); - state.push1(old); + state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmwCmpxchg { ref memarg } => { let (cmp, new) = state.pop2()?; @@ -8391,3 +8515,15 @@ impl ModuleCodeGenerator }) } } + +fn is_f32_arithmetic(bits: u32) -> bool { + // Mask off sign bit. + let bits = bits & 0x7FFF_FFFF; + bits < 0x7FC0_0000 +} + +fn is_f64_arithmetic(bits: u64) -> bool { + // Mask off sign bit. + let bits = bits & 0x7FFF_FFFF_FFFF_FFFF; + bits < 0x7FF8_0000_0000_0000 +} diff --git a/lib/llvm-backend/src/state.rs b/lib/llvm-backend/src/state.rs index c051dde0bd9..072d43324a2 100644 --- a/lib/llvm-backend/src/state.rs +++ b/lib/llvm-backend/src/state.rs @@ -4,7 +4,7 @@ use inkwell::{ }; use smallvec::SmallVec; use std::cell::Cell; -use std::ops::Add; +use std::ops::{BitAnd, BitOr, BitOrAssign}; use wasmparser::BinaryReaderError; #[derive(Debug)] @@ -111,18 +111,26 @@ impl ExtraInfo { pub fn is_arithmetic_f64(&self) -> bool { self.state & ExtraInfo::arithmetic_f64().state != 0 } + + pub fn strip_pending(&self) -> ExtraInfo { + ExtraInfo { + state: self.state + & !(ExtraInfo::arithmetic_f32().state | ExtraInfo::arithmetic_f64().state), + } + } } impl Default for ExtraInfo { fn default() -> Self { ExtraInfo { state: 0 } } } -impl Add for ExtraInfo { +// Union two ExtraInfos. +impl BitOr for ExtraInfo { type Output = Self; - fn add(self, other: Self) -> Self { - assert!(self.has_pending_f32_nan() && other.has_pending_f64_nan()); - assert!(self.has_pending_f64_nan() && other.has_pending_f32_nan()); + fn bitor(self, other: Self) -> Self { + assert!(!(self.has_pending_f32_nan() && other.has_pending_f64_nan())); + assert!(!(self.has_pending_f64_nan() && other.has_pending_f32_nan())); ExtraInfo { state: if self.is_arithmetic_f32() || other.is_arithmetic_f32() { ExtraInfo::arithmetic_f32().state @@ -140,6 +148,29 @@ impl Add for ExtraInfo { } } } +impl BitOrAssign for ExtraInfo { + fn bitor_assign(&mut self, other: Self) { + *self = *self | other; + } +} + +// Intersection for ExtraInfo. Does not check the "pending" bits, since those +// aren't safe to discard (or even to reorder). Callers are assumed to be in a +// situation where the result will have a pending bit set unconditionally. +impl BitAnd for ExtraInfo { + type Output = Self; + fn bitand(self, other: Self) -> Self { + match ( + self.is_arithmetic_f32() && other.is_arithmetic_f32(), + self.is_arithmetic_f64() && other.is_arithmetic_f64(), + ) { + (false, false) => Default::default(), + (true, false) => ExtraInfo::arithmetic_f32(), + (false, true) => ExtraInfo::arithmetic_f64(), + (true, true) => ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), + } + } +} #[derive(Debug)] pub struct State { @@ -251,15 +282,6 @@ impl State { Ok((v1, v2)) } - pub fn pop3( - &mut self, - ) -> Result<(BasicValueEnum, BasicValueEnum, BasicValueEnum), BinaryReaderError> { - let v3 = self.pop1()?; - let v2 = self.pop1()?; - let v1 = self.pop1()?; - Ok((v1, v2, v3)) - } - pub fn pop3_extra( &mut self, ) -> Result< From 284948b6d4c0603a1a425ed8a200b4e3103f1494 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Wed, 6 Nov 2019 20:45:50 -0800 Subject: [PATCH 268/342] Refactor so as to convert ExtraInfo when potentially canonicalizing. It seemed like a good idea at the time, but in practice we discard the extra info all or almost all of the time. This also introduces a new bug. In an operation like multiply, it's valid to multiply two values, one with a pending NaN and one without. As written, in the SIMD case (because of the two kinds of pending in play), we assert. --- lib/llvm-backend/src/code.rs | 745 ++++++++++++++++++++-------------- lib/llvm-backend/src/state.rs | 20 +- 2 files changed, 465 insertions(+), 300 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 5b8d078cc68..0bbc8e1b013 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -387,19 +387,28 @@ fn v128_into_int_vec( value: BasicValueEnum, info: ExtraInfo, int_vec_ty: VectorType, -) -> VectorValue { - let value = if info.has_pending_f32_nan() { +) -> (VectorValue, ExtraInfo) { + let (value, info) = if info.has_pending_f32_nan() { let value = builder.build_bitcast(value, intrinsics.f32x4_ty, ""); - canonicalize_nans(builder, intrinsics, value) + ( + canonicalize_nans(builder, intrinsics, value), + info.strip_pending(), + ) } else if info.has_pending_f64_nan() { let value = builder.build_bitcast(value, intrinsics.f64x2_ty, ""); - canonicalize_nans(builder, intrinsics, value) + ( + canonicalize_nans(builder, intrinsics, value), + info.strip_pending(), + ) } else { - value + (value, info) }; - builder - .build_bitcast(value, int_vec_ty, "") - .into_vector_value() + ( + builder + .build_bitcast(value, int_vec_ty, "") + .into_vector_value(), + info, + ) } fn v128_into_i8x16( @@ -407,7 +416,7 @@ fn v128_into_i8x16( intrinsics: &Intrinsics, value: BasicValueEnum, info: ExtraInfo, -) -> VectorValue { +) -> (VectorValue, ExtraInfo) { v128_into_int_vec(builder, intrinsics, value, info, intrinsics.i8x16_ty) } @@ -416,7 +425,7 @@ fn v128_into_i16x8( intrinsics: &Intrinsics, value: BasicValueEnum, info: ExtraInfo, -) -> VectorValue { +) -> (VectorValue, ExtraInfo) { v128_into_int_vec(builder, intrinsics, value, info, intrinsics.i16x8_ty) } @@ -425,7 +434,7 @@ fn v128_into_i32x4( intrinsics: &Intrinsics, value: BasicValueEnum, info: ExtraInfo, -) -> VectorValue { +) -> (VectorValue, ExtraInfo) { v128_into_int_vec(builder, intrinsics, value, info, intrinsics.i32x4_ty) } @@ -434,7 +443,7 @@ fn v128_into_i64x2( intrinsics: &Intrinsics, value: BasicValueEnum, info: ExtraInfo, -) -> VectorValue { +) -> (VectorValue, ExtraInfo) { v128_into_int_vec(builder, intrinsics, value, info, intrinsics.i64x2_ty) } @@ -445,16 +454,22 @@ fn v128_into_f32x4( intrinsics: &Intrinsics, value: BasicValueEnum, info: ExtraInfo, -) -> VectorValue { - let value = if info.has_pending_f64_nan() { +) -> (VectorValue, ExtraInfo) { + let (value, info) = if info.has_pending_f64_nan() { let value = builder.build_bitcast(value, intrinsics.f64x2_ty, ""); - canonicalize_nans(builder, intrinsics, value) + ( + canonicalize_nans(builder, intrinsics, value), + info.strip_pending(), + ) } else { - value + (value, info) }; - builder - .build_bitcast(value, intrinsics.f32x4_ty, "") - .into_vector_value() + ( + builder + .build_bitcast(value, intrinsics.f32x4_ty, "") + .into_vector_value(), + info, + ) } // If the value is pending a 32-bit canonicalization, do it now. @@ -464,16 +479,22 @@ fn v128_into_f64x2( intrinsics: &Intrinsics, value: BasicValueEnum, info: ExtraInfo, -) -> VectorValue { - let value = if info.has_pending_f32_nan() { +) -> (VectorValue, ExtraInfo) { + let (value, info) = if info.has_pending_f32_nan() { let value = builder.build_bitcast(value, intrinsics.f32x4_ty, ""); - canonicalize_nans(builder, intrinsics, value) + ( + canonicalize_nans(builder, intrinsics, value), + info.strip_pending(), + ) } else { - value + (value, info) }; - builder - .build_bitcast(value, intrinsics.f64x2_ty, "") - .into_vector_value() + ( + builder + .build_bitcast(value, intrinsics.f64x2_ty, "") + .into_vector_value(), + info, + ) } fn apply_pending_canonicalization( @@ -1737,7 +1758,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ); let res = builder.build_select(cond_value, v1, v2, &state.var_name()); let info = { - let mut info = i1 & i2; + let mut info = i1.strip_pending() & i2.strip_pending(); if i1.has_pending_f32_nan() { assert!(i2.has_pending_f32_nan()); info |= ExtraInfo::pending_f32_nan(); @@ -2120,49 +2141,55 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#integer-arithmetic-instructions ***************************/ Operator::I32Add | Operator::I64Add => { - 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_int_add(v1, v2, &state.var_name()); state.push1(res); } Operator::I8x16Add => { 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 (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, 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 (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, 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 (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, 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 (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, 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 (v1, _) = v128_into_i8x16(builder, intrinsics, v1, i1); + let (v2, _) = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder - .build_call(intrinsics.sadd_sat_i8x16, &[v1, v2], &state.var_name()) + .build_call( + intrinsics.sadd_sat_i8x16, + &[v1.as_basic_value_enum(), v2.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); @@ -2171,10 +2198,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I16x8AddSaturateS => { 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 (v1, _) = v128_into_i16x8(builder, intrinsics, v1, i1); + let (v2, _) = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder - .build_call(intrinsics.sadd_sat_i16x8, &[v1, v2], &state.var_name()) + .build_call( + intrinsics.sadd_sat_i16x8, + &[v1.as_basic_value_enum(), v2.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); @@ -2183,10 +2214,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I8x16AddSaturateU => { 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 (v1, _) = v128_into_i8x16(builder, intrinsics, v1, i1); + let (v2, _) = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder - .build_call(intrinsics.uadd_sat_i8x16, &[v1, v2], &state.var_name()) + .build_call( + intrinsics.uadd_sat_i8x16, + &[v1.as_basic_value_enum(), v2.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); @@ -2195,10 +2230,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I16x8AddSaturateU => { 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 (v1, _) = v128_into_i16x8(builder, intrinsics, v1, i1); + let (v2, _) = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder - .build_call(intrinsics.uadd_sat_i16x8, &[v1, v2], &state.var_name()) + .build_call( + intrinsics.uadd_sat_i16x8, + &[v1.as_basic_value_enum(), v2.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); @@ -2206,49 +2245,55 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32Sub | Operator::I64Sub => { - 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_int_sub(v1, v2, &state.var_name()); state.push1(res); } Operator::I8x16Sub => { 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 (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, 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 (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, 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 (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, 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 (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, 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 (v1, _) = v128_into_i8x16(builder, intrinsics, v1, i1); + let (v2, _) = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder - .build_call(intrinsics.ssub_sat_i8x16, &[v1, v2], &state.var_name()) + .build_call( + intrinsics.ssub_sat_i8x16, + &[v1.as_basic_value_enum(), v2.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); @@ -2257,10 +2302,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I16x8SubSaturateS => { 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 (v1, _) = v128_into_i16x8(builder, intrinsics, v1, i1); + let (v2, _) = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder - .build_call(intrinsics.ssub_sat_i16x8, &[v1, v2], &state.var_name()) + .build_call( + intrinsics.ssub_sat_i16x8, + &[v1.as_basic_value_enum(), v2.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); @@ -2269,10 +2318,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I8x16SubSaturateU => { 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 (v1, _) = v128_into_i8x16(builder, intrinsics, v1, i1); + let (v2, _) = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder - .build_call(intrinsics.usub_sat_i8x16, &[v1, v2], &state.var_name()) + .build_call( + intrinsics.usub_sat_i8x16, + &[v1.as_basic_value_enum(), v2.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); @@ -2281,10 +2334,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I16x8SubSaturateU => { 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 (v1, _) = v128_into_i16x8(builder, intrinsics, v1, i1); + let (v2, _) = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder - .build_call(intrinsics.usub_sat_i16x8, &[v1, v2], &state.var_name()) + .build_call( + intrinsics.usub_sat_i16x8, + &[v1.as_basic_value_enum(), v2.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); @@ -2292,37 +2349,41 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32Mul | Operator::I64Mul => { - 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_int_mul(v1, v2, &state.var_name()); state.push1(res); } Operator::I8x16Mul => { 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 (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, 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 (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, 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 (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); } Operator::I32DivS | Operator::I64DivS => { - 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()); trap_if_zero_or_overflow(builder, intrinsics, context, &function, v1, v2); @@ -2331,7 +2392,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32DivU | Operator::I64DivU => { - 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()); trap_if_zero(builder, intrinsics, context, &function, v2); @@ -2340,7 +2403,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32RemS | Operator::I64RemS => { - 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 int_type = v1.get_type(); let (min_value, neg_one_value) = if int_type == intrinsics.i32_ty { @@ -2385,7 +2450,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32RemU | Operator::I64RemU => { - 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()); trap_if_zero(builder, intrinsics, context, &function, v2); @@ -2436,15 +2503,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32Shl | Operator::I64Shl => { - 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()); // TODO: missing 'and' of v2? let res = builder.build_left_shift(v1, v2, &state.var_name()); state.push1(res); } Operator::I8x16Shl => { - let ((v1, i1), (v2, _)) = state.pop2_extra()?; - let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let (v1, _) = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); 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, ""); @@ -2460,8 +2530,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8Shl => { - let ((v1, i1), (v2, _)) = state.pop2_extra()?; - let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let (v1, _) = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); 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, ""); @@ -2477,8 +2548,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32x4Shl => { - let ((v1, i1), (v2, _)) = state.pop2_extra()?; - let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let (v1, _) = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(31, false), ""); let v2 = splat_vector( @@ -2493,8 +2565,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I64x2Shl => { - let ((v1, i1), (v2, _)) = state.pop2_extra()?; - let v1 = v128_into_i64x2(builder, intrinsics, v1, i1); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let (v1, _) = v128_into_i64x2(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); 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, ""); @@ -2510,15 +2583,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32ShrS | Operator::I64ShrS => { - 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()); // TODO: check wasm spec, is this missing v2 mod LaneBits? let res = builder.build_right_shift(v1, v2, true, &state.var_name()); state.push1(res); } Operator::I8x16ShrS => { - let ((v1, i1), (v2, _)) = state.pop2_extra()?; - let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let (v1, _) = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); 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, ""); @@ -2534,8 +2610,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8ShrS => { - let ((v1, i1), (v2, _)) = state.pop2_extra()?; - let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let (v1, _) = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); 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, ""); @@ -2551,8 +2628,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32x4ShrS => { - let ((v1, i1), (v2, _)) = state.pop2_extra()?; - let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let (v1, _) = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(31, false), ""); let v2 = splat_vector( @@ -2567,8 +2645,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I64x2ShrS => { - let ((v1, i1), (v2, _)) = state.pop2_extra()?; - let v1 = v128_into_i64x2(builder, intrinsics, v1, i1); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let (v1, _) = v128_into_i64x2(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); 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, ""); @@ -2584,14 +2663,17 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32ShrU | Operator::I64ShrU => { - 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_right_shift(v1, v2, false, &state.var_name()); state.push1(res); } Operator::I8x16ShrU => { - let ((v1, i1), (v2, _)) = state.pop2_extra()?; - let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let (v1, _) = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); 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, ""); @@ -2607,8 +2689,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8ShrU => { - let ((v1, i1), (v2, _)) = state.pop2_extra()?; - let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let (v1, _) = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); 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, ""); @@ -2624,8 +2707,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32x4ShrU => { - let ((v1, i1), (v2, _)) = state.pop2_extra()?; - let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let (v1, _) = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(31, false), ""); let v2 = splat_vector( @@ -2640,8 +2724,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I64x2ShrU => { - let ((v1, i1), (v2, _)) = state.pop2_extra()?; - let v1 = v128_into_i64x2(builder, intrinsics, v1, i1); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let (v1, _) = v128_into_i64x2(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); 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, ""); @@ -2657,7 +2742,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32Rotl => { - 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 lhs = builder.build_left_shift(v1, v2, &state.var_name()); let rhs = { @@ -2669,7 +2756,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I64Rotl => { - 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 lhs = builder.build_left_shift(v1, v2, &state.var_name()); let rhs = { @@ -2681,7 +2770,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32Rotr => { - 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 lhs = builder.build_right_shift(v1, v2, false, &state.var_name()); let rhs = { @@ -2693,7 +2784,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I64Rotr => { - 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 lhs = builder.build_right_shift(v1, v2, false, &state.var_name()); let rhs = { @@ -2705,7 +2798,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32Clz => { - let input = state.pop1()?; + let (input, info) = state.pop1_extra()?; + let input = apply_pending_canonicalization(builder, intrinsics, input, info); let is_zero_undef = intrinsics.i1_zero.as_basic_value_enum(); let res = builder .build_call( @@ -2719,7 +2813,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1_extra(res, ExtraInfo::arithmetic_f32()); } Operator::I64Clz => { - let input = state.pop1()?; + let (input, info) = state.pop1_extra()?; + let input = apply_pending_canonicalization(builder, intrinsics, input, info); let is_zero_undef = intrinsics.i1_zero.as_basic_value_enum(); let res = builder .build_call( @@ -2733,7 +2828,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1_extra(res, ExtraInfo::arithmetic_f64()); } Operator::I32Ctz => { - let input = state.pop1()?; + let (input, info) = state.pop1_extra()?; + let input = apply_pending_canonicalization(builder, intrinsics, input, info); let is_zero_undef = intrinsics.i1_zero.as_basic_value_enum(); let res = builder .build_call( @@ -2747,7 +2843,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1_extra(res, ExtraInfo::arithmetic_f32()); } Operator::I64Ctz => { - let input = state.pop1()?; + let (input, info) = state.pop1_extra()?; + let input = apply_pending_canonicalization(builder, intrinsics, input, info); let is_zero_undef = intrinsics.i1_zero.as_basic_value_enum(); let res = builder .build_call( @@ -2761,7 +2858,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1_extra(res, ExtraInfo::arithmetic_f64()); } Operator::I32Popcnt => { - let input = state.pop1()?; + let (input, info) = state.pop1_extra()?; + let input = apply_pending_canonicalization(builder, intrinsics, input, info); let res = builder .build_call(intrinsics.ctpop_i32, &[input], &state.var_name()) .try_as_basic_value() @@ -2770,7 +2868,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1_extra(res, ExtraInfo::arithmetic_f32()); } Operator::I64Popcnt => { - let input = state.pop1()?; + let (input, info) = state.pop1_extra()?; + let input = apply_pending_canonicalization(builder, intrinsics, input, info); let res = builder .build_call(intrinsics.ctpop_i64, &[input], &state.var_name()) .try_as_basic_value() @@ -2808,27 +2907,29 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Operator::F32Add => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let (i1, i2) = (i1.strip_pending(), i2.strip_pending()); let res = builder.build_float_add(v1, v2, &state.var_name()); state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f32_nan()); } Operator::F64Add => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let (i1, i2) = (i1.strip_pending(), i2.strip_pending()); let res = builder.build_float_add(v1, v2, &state.var_name()); state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f64_nan()); } Operator::F32x4Add => { 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 (v1, i1) = v128_into_f32x4(builder, intrinsics, v1, i1); + let (v2, i2) = 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_extra(res, (i1 & i2) | ExtraInfo::pending_f32_nan()); } Operator::F64x2Add => { 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 (v1, i1) = v128_into_f64x2(builder, intrinsics, v1, i1); + let (v2, i2) = 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_extra(res, (i1 & i2) | ExtraInfo::pending_f64_nan()); @@ -2836,27 +2937,29 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Operator::F32Sub => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let (i1, i2) = (i1.strip_pending(), i2.strip_pending()); let res = builder.build_float_sub(v1, v2, &state.var_name()); state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f32_nan()); } Operator::F64Sub => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let (i1, i2) = (i1.strip_pending(), i2.strip_pending()); let res = builder.build_float_sub(v1, v2, &state.var_name()); state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f64_nan()); } Operator::F32x4Sub => { 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 (v1, i1) = v128_into_f32x4(builder, intrinsics, v1, i1); + let (v2, i2) = 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_extra(res, (i1 & i2) | ExtraInfo::pending_f32_nan()); } Operator::F64x2Sub => { 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 (v1, i1) = v128_into_f64x2(builder, intrinsics, v1, i1); + let (v2, i2) = 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_extra(res, (i1 & i2) | ExtraInfo::pending_f64_nan()); @@ -2864,27 +2967,29 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Operator::F32Mul => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let (i1, i2) = (i1.strip_pending(), i2.strip_pending()); let res = builder.build_float_mul(v1, v2, &state.var_name()); state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f32_nan()); } Operator::F64Mul => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let (i1, i2) = (i1.strip_pending(), i2.strip_pending()); let res = builder.build_float_mul(v1, v2, &state.var_name()); state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f64_nan()); } Operator::F32x4Mul => { 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 (v1, i1) = v128_into_f32x4(builder, intrinsics, v1, i1); + let (v2, i2) = 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_extra(res, (i1 & i2) | ExtraInfo::pending_f32_nan()); } Operator::F64x2Mul => { 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 (v1, i1) = v128_into_f64x2(builder, intrinsics, v1, i1); + let (v2, i2) = 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_extra(res, (i1 & i2) | ExtraInfo::pending_f64_nan()); @@ -2903,16 +3008,16 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F32x4Div => { 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 (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_extra(res, ExtraInfo::pending_f32_nan()); } Operator::F64x2Div => { 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 (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_extra(res, ExtraInfo::pending_f64_nan()); @@ -2937,7 +3042,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F32x4Sqrt => { let (v, i) = state.pop1_extra()?; - let v = v128_into_f32x4(builder, intrinsics, v, i); + let (v, _) = v128_into_f32x4(builder, intrinsics, v, i); let res = builder .build_call( intrinsics.sqrt_f32x4, @@ -2952,7 +3057,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F64x2Sqrt => { let (v, i) = state.pop1_extra()?; - let v = v128_into_f64x2(builder, intrinsics, v, i); + let (v, _) = v128_into_f64x2(builder, intrinsics, v, i); let res = builder .build_call( intrinsics.sqrt_f64x2, @@ -3078,8 +3183,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { // intrinsic would, but x86 lowering of that intrinsic // encounters a fatal error in LLVM 8 and LLVM 9. 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 (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 @@ -3144,8 +3249,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { // intrinsic would, but x86 lowering of that intrinsic // encounters a fatal error in LLVM 8 and LLVM 9. 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 (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 @@ -3316,8 +3421,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { // intrinsic would, but x86 lowering of that intrinsic // encounters a fatal error in LLVM 8 and LLVM 9. 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 (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 @@ -3381,8 +3486,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { // intrinsic would, but x86 lowering of that intrinsic // encounters a fatal error in LLVM 8 and LLVM 9. 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 (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 @@ -3656,7 +3761,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#integer-comparison-instructions ***************************/ Operator::I32Eq | Operator::I64Eq => { - 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 cond = builder.build_int_compare(IntPredicate::EQ, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); @@ -3667,8 +3774,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I8x16Eq => { 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 (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, ""); @@ -3676,8 +3783,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I16x8Eq => { 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 (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, ""); @@ -3685,15 +3792,17 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I32x4Eq => { 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 (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, ""); state.push1(res); } Operator::I32Ne | Operator::I64Ne => { - 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 cond = builder.build_int_compare(IntPredicate::NE, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); @@ -3704,8 +3813,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I8x16Ne => { 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 (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, ""); @@ -3713,8 +3822,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I16x8Ne => { 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 (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, ""); @@ -3722,15 +3831,17 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I32x4Ne => { 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 (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, ""); state.push1(res); } Operator::I32LtS | Operator::I64LtS => { - 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 cond = builder.build_int_compare(IntPredicate::SLT, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); @@ -3741,8 +3852,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I8x16LtS => { 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 (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, ""); @@ -3750,8 +3861,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I16x8LtS => { 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 (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, ""); @@ -3759,15 +3870,17 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I32x4LtS => { 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 (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, ""); state.push1(res); } Operator::I32LtU | Operator::I64LtU => { - 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 cond = builder.build_int_compare(IntPredicate::ULT, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); @@ -3775,8 +3888,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I8x16LtU => { 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 (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, ""); @@ -3784,8 +3897,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I16x8LtU => { 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 (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, ""); @@ -3793,15 +3906,17 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I32x4LtU => { 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 (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, ""); state.push1(res); } Operator::I32LeS | Operator::I64LeS => { - 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 cond = builder.build_int_compare(IntPredicate::SLE, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); @@ -3812,8 +3927,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I8x16LeS => { 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 (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, ""); @@ -3821,8 +3936,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I16x8LeS => { 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 (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, ""); @@ -3830,15 +3945,17 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I32x4LeS => { 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 (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, ""); state.push1(res); } Operator::I32LeU | Operator::I64LeU => { - 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 cond = builder.build_int_compare(IntPredicate::ULE, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); @@ -3849,8 +3966,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I8x16LeU => { 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 (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, ""); @@ -3858,8 +3975,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I16x8LeU => { 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 (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, ""); @@ -3867,15 +3984,17 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I32x4LeU => { 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 (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, ""); state.push1(res); } Operator::I32GtS | Operator::I64GtS => { - 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 cond = builder.build_int_compare(IntPredicate::SGT, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); @@ -3886,8 +4005,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I8x16GtS => { 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 (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, ""); @@ -3895,8 +4014,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I16x8GtS => { 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 (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, ""); @@ -3904,15 +4023,17 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I32x4GtS => { 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 (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, ""); state.push1(res); } Operator::I32GtU | Operator::I64GtU => { - 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 cond = builder.build_int_compare(IntPredicate::UGT, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); @@ -3923,8 +4044,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I8x16GtU => { 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 (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, ""); @@ -3932,8 +4053,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I16x8GtU => { 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 (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, ""); @@ -3941,15 +4062,17 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I32x4GtU => { 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 (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, ""); state.push1(res); } Operator::I32GeS | Operator::I64GeS => { - 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 cond = builder.build_int_compare(IntPredicate::SGE, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); @@ -3957,8 +4080,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I8x16GeS => { 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 (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, ""); @@ -3966,8 +4089,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I16x8GeS => { 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 (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, ""); @@ -3975,15 +4098,17 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I32x4GeS => { 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 (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, ""); state.push1(res); } Operator::I32GeU | Operator::I64GeU => { - 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 cond = builder.build_int_compare(IntPredicate::UGE, v1, v2, &state.var_name()); let res = builder.build_int_z_extend(cond, intrinsics.i32_ty, &state.var_name()); @@ -3994,8 +4119,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I8x16GeU => { 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 (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, ""); @@ -4003,8 +4128,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I16x8GeU => { 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 (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, ""); @@ -4012,8 +4137,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I32x4GeU => { 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 (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, ""); @@ -4037,8 +4162,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F32x4Eq => { 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 (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, ""); @@ -4046,8 +4171,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F64x2Eq => { 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 (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, ""); @@ -4066,8 +4191,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F32x4Ne => { 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 (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, ""); @@ -4075,8 +4200,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F64x2Ne => { 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 (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, ""); @@ -4095,8 +4220,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F32x4Lt => { 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 (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, ""); @@ -4104,8 +4229,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F64x2Lt => { 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 (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, ""); @@ -4124,8 +4249,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F32x4Le => { 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 (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, ""); @@ -4133,8 +4258,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F64x2Le => { 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 (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, ""); @@ -4153,8 +4278,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F32x4Gt => { 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 (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, ""); @@ -4162,8 +4287,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F64x2Gt => { 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 (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, ""); @@ -4182,8 +4307,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F32x4Ge => { 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 (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, ""); @@ -4191,8 +4316,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F64x2Ge => { 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 (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, ""); @@ -4204,22 +4329,30 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#conversion-instructions ***************************/ Operator::I32WrapI64 => { - let v1 = state.pop1()?.into_int_value(); - let res = builder.build_int_truncate(v1, intrinsics.i32_ty, &state.var_name()); + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); + let v = v.into_int_value(); + let res = builder.build_int_truncate(v, intrinsics.i32_ty, &state.var_name()); state.push1(res); } Operator::I64ExtendSI32 => { - let v1 = state.pop1()?.into_int_value(); - let res = builder.build_int_s_extend(v1, intrinsics.i64_ty, &state.var_name()); + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); + let v = v.into_int_value(); + let res = builder.build_int_s_extend(v, intrinsics.i64_ty, &state.var_name()); state.push1(res); } Operator::I64ExtendUI32 => { - let v1 = state.pop1()?.into_int_value(); - let res = builder.build_int_z_extend(v1, intrinsics.i64_ty, &state.var_name()); + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); + let v = v.into_int_value(); + let res = builder.build_int_z_extend(v, intrinsics.i64_ty, &state.var_name()); state.push1_extra(res, ExtraInfo::arithmetic_f64()); } Operator::I32x4TruncSF32x4Sat => { - let v = state.pop1()?.into_int_value(); + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); + let v = v.into_int_value(); let res = trunc_sat( builder, intrinsics, @@ -4235,7 +4368,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32x4TruncUF32x4Sat => { - let v = state.pop1()?.into_int_value(); + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); + let v = v.into_int_value(); let res = trunc_sat( builder, intrinsics, @@ -4251,7 +4386,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I64x2TruncSF64x2Sat => { - let v = state.pop1()?.into_int_value(); + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); + let v = v.into_int_value(); let res = trunc_sat( builder, intrinsics, @@ -4267,7 +4404,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I64x2TruncUF64x2Sat => { - let v = state.pop1()?.into_int_value(); + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); + let v = v.into_int_value(); let res = trunc_sat( builder, intrinsics, @@ -4424,27 +4563,35 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1_extra(res, ExtraInfo::pending_f64_nan()); } Operator::F32ConvertSI32 | Operator::F32ConvertSI64 => { - let v1 = state.pop1()?.into_int_value(); + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); + let v = v.into_int_value(); let res = - builder.build_signed_int_to_float(v1, intrinsics.f32_ty, &state.var_name()); + builder.build_signed_int_to_float(v, intrinsics.f32_ty, &state.var_name()); state.push1(res); } Operator::F64ConvertSI32 | Operator::F64ConvertSI64 => { - let v1 = state.pop1()?.into_int_value(); + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); + let v = v.into_int_value(); let res = - builder.build_signed_int_to_float(v1, intrinsics.f64_ty, &state.var_name()); + builder.build_signed_int_to_float(v, intrinsics.f64_ty, &state.var_name()); state.push1(res); } Operator::F32ConvertUI32 | Operator::F32ConvertUI64 => { - let v1 = state.pop1()?.into_int_value(); + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); + let v = v.into_int_value(); let res = - builder.build_unsigned_int_to_float(v1, intrinsics.f32_ty, &state.var_name()); + builder.build_unsigned_int_to_float(v, intrinsics.f32_ty, &state.var_name()); state.push1(res); } Operator::F64ConvertUI32 | Operator::F64ConvertUI64 => { - let v1 = state.pop1()?.into_int_value(); + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); + let v = v.into_int_value(); let res = - builder.build_unsigned_int_to_float(v1, intrinsics.f64_ty, &state.var_name()); + builder.build_unsigned_int_to_float(v, intrinsics.f64_ty, &state.var_name()); state.push1(res); } Operator::F32x4ConvertSI32x4 => { @@ -5185,28 +5332,28 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I8x16Neg => { let (v, i) = state.pop1_extra()?; - let v = v128_into_i8x16(builder, intrinsics, v, i); + 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, i) = state.pop1_extra()?; - let v = v128_into_i16x8(builder, intrinsics, v, i); + 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, i) = state.pop1_extra()?; - let v = v128_into_i32x4(builder, intrinsics, v, i); + 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, i) = state.pop1_extra()?; - let v = v128_into_i64x2(builder, intrinsics, v, i); + 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); @@ -5221,8 +5368,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { | Operator::I16x8AnyTrue | Operator::I32x4AnyTrue | Operator::I64x2AnyTrue => { - let (v, i) = state.pop1_extra()?; - let v = apply_pending_canonicalization(builder, intrinsics, v, i).into_int_value(); + // Skip canonicalization, it never changes non-zero values to zero or vice versa. + let v = state.pop1()?.into_int_value(); let res = builder.build_int_compare( IntPredicate::NE, v, @@ -5269,7 +5416,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I8x16ExtractLaneS { lane } => { let (v, i) = state.pop1_extra()?; - let v = v128_into_i8x16(builder, intrinsics, v, i); + 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()) @@ -5279,7 +5426,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I8x16ExtractLaneU { lane } => { let (v, i) = state.pop1_extra()?; - let v = v128_into_i8x16(builder, intrinsics, v, i); + 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()) @@ -5289,7 +5436,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I16x8ExtractLaneS { lane } => { let (v, i) = state.pop1_extra()?; - let v = v128_into_i16x8(builder, intrinsics, v, i); + 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()) @@ -5299,7 +5446,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I16x8ExtractLaneU { lane } => { let (v, i) = state.pop1_extra()?; - let v = v128_into_i16x8(builder, intrinsics, v, i); + 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()) @@ -5309,45 +5456,35 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I32x4ExtractLane { lane } => { let (v, i) = state.pop1_extra()?; - let v = v128_into_i32x4(builder, intrinsics, v, i); + let (v, i) = 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_extra(res, i.strip_pending()); + state.push1_extra(res, i); } Operator::I64x2ExtractLane { lane } => { let (v, i) = state.pop1_extra()?; - let v = v128_into_i64x2(builder, intrinsics, v, i); + let (v, i) = 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_extra(res, i.strip_pending()); + state.push1_extra(res, i); } Operator::F32x4ExtractLane { lane } => { let (v, i) = state.pop1_extra()?; - let v = v128_into_f32x4(builder, intrinsics, v, i); + let (v, i) = 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()); - let i = if i.has_pending_f64_nan() { - i.strip_pending() - } else { - i - }; state.push1_extra(res, i); } Operator::F64x2ExtractLane { lane } => { let (v, i) = state.pop1_extra()?; - let v = v128_into_f64x2(builder, intrinsics, v, i); + let (v, i) = 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()); - let i = if i.has_pending_f32_nan() { - i.strip_pending() - } else { - i - }; state.push1_extra(res, i); } Operator::I8x16ReplaceLane { lane } => { let ((v1, i1), (v2, _)) = state.pop2_extra()?; - let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + 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); @@ -5357,7 +5494,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I16x8ReplaceLane { lane } => { let ((v1, i1), (v2, _)) = state.pop2_extra()?; - let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + 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); @@ -5367,8 +5504,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I32x4ReplaceLane { lane } => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; - let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let (v1, i1) = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); let v2 = v2.into_int_value(); + let i2 = i2.strip_pending(); 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, ""); @@ -5376,8 +5515,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I64x2ReplaceLane { lane } => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; - let v1 = v128_into_i64x2(builder, intrinsics, v1, i1); + let (v1, i1) = v128_into_i64x2(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); let v2 = v2.into_int_value(); + let i2 = i2.strip_pending(); 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, ""); @@ -5385,9 +5526,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F32x4ReplaceLane { lane } => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; - let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let (v1, i1) = v128_into_f32x4(builder, intrinsics, v1, i1); let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2).into_float_value(); + let i2 = i2.strip_pending(); 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, ""); @@ -5395,9 +5537,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F64x2ReplaceLane { lane } => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; - let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let (v1, i1) = v128_into_f64x2(builder, intrinsics, v1, i1); let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2).into_float_value(); + let i2 = i2.strip_pending(); 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, ""); @@ -7741,7 +7884,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(old); } Operator::I32AtomicRmw8UCmpxchg { ref memarg } => { - let (cmp, new) = state.pop2()?; + let ((cmp, cmp_info), (new, new_info)) = state.pop2_extra()?; + let cmp = apply_pending_canonicalization(builder, intrinsics, cmp, cmp_info); + let new = apply_pending_canonicalization(builder, intrinsics, new, new_info); let (cmp, new) = (cmp.into_int_value(), new.into_int_value()); let effective_address = resolve_memory_ptr( builder, @@ -7791,7 +7936,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmw16UCmpxchg { ref memarg } => { - let (cmp, new) = state.pop2()?; + let ((cmp, cmp_info), (new, new_info)) = state.pop2_extra()?; + let cmp = apply_pending_canonicalization(builder, intrinsics, cmp, cmp_info); + let new = apply_pending_canonicalization(builder, intrinsics, new, new_info); let (cmp, new) = (cmp.into_int_value(), new.into_int_value()); let effective_address = resolve_memory_ptr( builder, @@ -7841,7 +7988,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1_extra(old, ExtraInfo::arithmetic_f32()); } Operator::I32AtomicRmwCmpxchg { ref memarg } => { - let (cmp, new) = state.pop2()?; + let ((cmp, cmp_info), (new, new_info)) = state.pop2_extra()?; + let cmp = apply_pending_canonicalization(builder, intrinsics, cmp, cmp_info); + let new = apply_pending_canonicalization(builder, intrinsics, new, new_info); let (cmp, new) = (cmp.into_int_value(), new.into_int_value()); let effective_address = resolve_memory_ptr( builder, @@ -7883,7 +8032,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(old); } Operator::I64AtomicRmw8UCmpxchg { ref memarg } => { - let (cmp, new) = state.pop2()?; + let ((cmp, cmp_info), (new, new_info)) = state.pop2_extra()?; + let cmp = apply_pending_canonicalization(builder, intrinsics, cmp, cmp_info); + let new = apply_pending_canonicalization(builder, intrinsics, new, new_info); let (cmp, new) = (cmp.into_int_value(), new.into_int_value()); let effective_address = resolve_memory_ptr( builder, @@ -7933,7 +8084,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw16UCmpxchg { ref memarg } => { - let (cmp, new) = state.pop2()?; + let ((cmp, cmp_info), (new, new_info)) = state.pop2_extra()?; + let cmp = apply_pending_canonicalization(builder, intrinsics, cmp, cmp_info); + let new = apply_pending_canonicalization(builder, intrinsics, new, new_info); let (cmp, new) = (cmp.into_int_value(), new.into_int_value()); let effective_address = resolve_memory_ptr( builder, @@ -7983,7 +8136,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmw32UCmpxchg { ref memarg } => { - let (cmp, new) = state.pop2()?; + let ((cmp, cmp_info), (new, new_info)) = state.pop2_extra()?; + let cmp = apply_pending_canonicalization(builder, intrinsics, cmp, cmp_info); + let new = apply_pending_canonicalization(builder, intrinsics, new, new_info); let (cmp, new) = (cmp.into_int_value(), new.into_int_value()); let effective_address = resolve_memory_ptr( builder, @@ -8033,7 +8188,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1_extra(old, ExtraInfo::arithmetic_f64()); } Operator::I64AtomicRmwCmpxchg { ref memarg } => { - let (cmp, new) = state.pop2()?; + let ((cmp, cmp_info), (new, new_info)) = state.pop2_extra()?; + let cmp = apply_pending_canonicalization(builder, intrinsics, cmp, cmp_info); + let new = apply_pending_canonicalization(builder, intrinsics, new, new_info); let (cmp, new) = (cmp.into_int_value(), new.into_int_value()); let effective_address = resolve_memory_ptr( builder, diff --git a/lib/llvm-backend/src/state.rs b/lib/llvm-backend/src/state.rs index 072d43324a2..82dbdbcf415 100644 --- a/lib/llvm-backend/src/state.rs +++ b/lib/llvm-backend/src/state.rs @@ -115,7 +115,7 @@ impl ExtraInfo { pub fn strip_pending(&self) -> ExtraInfo { ExtraInfo { state: self.state - & !(ExtraInfo::arithmetic_f32().state | ExtraInfo::arithmetic_f64().state), + & !(ExtraInfo::pending_f32_nan().state | ExtraInfo::pending_f64_nan().state), } } } @@ -154,13 +154,14 @@ impl BitOrAssign for ExtraInfo { } } -// Intersection for ExtraInfo. Does not check the "pending" bits, since those -// aren't safe to discard (or even to reorder). Callers are assumed to be in a -// situation where the result will have a pending bit set unconditionally. +// Intersection for ExtraInfo. impl BitAnd for ExtraInfo { type Output = Self; fn bitand(self, other: Self) -> Self { - match ( + // Pending canonicalizations are not safe to discard, or even reorder. + assert!(self.has_pending_f32_nan() == other.has_pending_f32_nan()); + assert!(self.has_pending_f64_nan() == other.has_pending_f64_nan()); + let info = match ( self.is_arithmetic_f32() && other.is_arithmetic_f32(), self.is_arithmetic_f64() && other.is_arithmetic_f64(), ) { @@ -168,7 +169,14 @@ impl BitAnd for ExtraInfo { (true, false) => ExtraInfo::arithmetic_f32(), (false, true) => ExtraInfo::arithmetic_f64(), (true, true) => ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), - } + }; + let info = match (self.has_pending_f32_nan(), self.has_pending_f64_nan()) { + (false, false) => info, + (true, false) => info | ExtraInfo::pending_f32_nan(), + (false, true) => info | ExtraInfo::pending_f64_nan(), + (true, true) => panic!(""), + }; + info } } From a06c858087f166e77d7fffe037b922d88e049497 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Wed, 6 Nov 2019 22:54:14 -0800 Subject: [PATCH 269/342] Make ExtraInfo bitand check for pending validity. Unfortunately, this is quite buggy. For something as simple as F32Sub, to combine two ExtraInfos, we want to add a new pending_f32_nan(), unless both of the inputs are arithmetic_f32(). In this commit, we incorrectly calculate that we don't need a pending_f32_nan if either one of the inputs was arithmetic_f32(). --- lib/llvm-backend/src/code.rs | 118 ++++++++++++++++++++++++++-------- lib/llvm-backend/src/state.rs | 12 +++- 2 files changed, 102 insertions(+), 28 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 0bbc8e1b013..392f931e299 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -2907,92 +2907,110 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Operator::F32Add => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let (i1, i2) = (i1.strip_pending(), i2.strip_pending()); + let i1 = i1 | ExtraInfo::pending_f32_nan(); + let i2 = i2 | ExtraInfo::pending_f32_nan(); let res = builder.build_float_add(v1, v2, &state.var_name()); - state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f32_nan()); + state.push1_extra(res, i1 & i2); } Operator::F64Add => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let (i1, i2) = (i1.strip_pending(), i2.strip_pending()); + let i1 = i1 | ExtraInfo::pending_f64_nan(); + let i2 = i2 | ExtraInfo::pending_f64_nan(); let res = builder.build_float_add(v1, v2, &state.var_name()); - state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f64_nan()); + state.push1_extra(res, i1 & i2); } Operator::F32x4Add => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, i1) = v128_into_f32x4(builder, intrinsics, v1, i1); let (v2, i2) = v128_into_f32x4(builder, intrinsics, v2, i2); + let i1 = i1 | ExtraInfo::pending_f32_nan(); + let i2 = i2 | ExtraInfo::pending_f32_nan(); let res = builder.build_float_add(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f32_nan()); + state.push1_extra(res, i1 & i2); } Operator::F64x2Add => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, i1) = v128_into_f64x2(builder, intrinsics, v1, i1); let (v2, i2) = v128_into_f64x2(builder, intrinsics, v2, i2); + let i1 = i1 | ExtraInfo::pending_f64_nan(); + let i2 = i2 | ExtraInfo::pending_f64_nan(); let res = builder.build_float_add(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f64_nan()); + state.push1_extra(res, i1 & i2); } Operator::F32Sub => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let (i1, i2) = (i1.strip_pending(), i2.strip_pending()); + let i1 = i1 | ExtraInfo::pending_f32_nan(); + let i2 = i2 | ExtraInfo::pending_f32_nan(); let res = builder.build_float_sub(v1, v2, &state.var_name()); - state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f32_nan()); + state.push1_extra(res, i1 & i2); } Operator::F64Sub => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let (i1, i2) = (i1.strip_pending(), i2.strip_pending()); + let i1 = i1 | ExtraInfo::pending_f64_nan(); + let i2 = i2 | ExtraInfo::pending_f64_nan(); let res = builder.build_float_sub(v1, v2, &state.var_name()); - state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f64_nan()); + state.push1_extra(res, i1 & i2); } Operator::F32x4Sub => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, i1) = v128_into_f32x4(builder, intrinsics, v1, i1); let (v2, i2) = v128_into_f32x4(builder, intrinsics, v2, i2); + let i1 = i1 | ExtraInfo::pending_f32_nan(); + let i2 = i2 | ExtraInfo::pending_f32_nan(); let res = builder.build_float_sub(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f32_nan()); + state.push1_extra(res, i1 & i2); } Operator::F64x2Sub => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, i1) = v128_into_f64x2(builder, intrinsics, v1, i1); let (v2, i2) = v128_into_f64x2(builder, intrinsics, v2, i2); + let i1 = i1 | ExtraInfo::pending_f64_nan(); + let i2 = i2 | ExtraInfo::pending_f64_nan(); let res = builder.build_float_sub(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f64_nan()); + state.push1_extra(res, i1 & i2); } Operator::F32Mul => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let (i1, i2) = (i1.strip_pending(), i2.strip_pending()); + let i1 = i1 | ExtraInfo::pending_f32_nan(); + let i2 = i2 | ExtraInfo::pending_f32_nan(); let res = builder.build_float_mul(v1, v2, &state.var_name()); - state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f32_nan()); + state.push1_extra(res, i1 & i2); } Operator::F64Mul => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let (i1, i2) = (i1.strip_pending(), i2.strip_pending()); + let i1 = i1 | ExtraInfo::pending_f64_nan(); + let i2 = i2 | ExtraInfo::pending_f64_nan(); let res = builder.build_float_mul(v1, v2, &state.var_name()); - state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f64_nan()); + state.push1_extra(res, i1 & i2); } Operator::F32x4Mul => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, i1) = v128_into_f32x4(builder, intrinsics, v1, i1); let (v2, i2) = v128_into_f32x4(builder, intrinsics, v2, i2); + let i1 = i1 | ExtraInfo::pending_f32_nan(); + let i2 = i2 | ExtraInfo::pending_f32_nan(); let res = builder.build_float_mul(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f32_nan()); + state.push1_extra(res, i1 & i2); } Operator::F64x2Mul => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, i1) = v128_into_f64x2(builder, intrinsics, v1, i1); let (v2, i2) = v128_into_f64x2(builder, intrinsics, v2, i2); + let i1 = i1 | ExtraInfo::pending_f64_nan(); + let i2 = i2 | ExtraInfo::pending_f64_nan(); let res = builder.build_float_mul(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1_extra(res, (i1 & i2) | ExtraInfo::pending_f64_nan()); + state.push1_extra(res, i1 & i2); } Operator::F32Div => { let (v1, v2) = state.pop2()?; @@ -5527,24 +5545,72 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Operator::F32x4ReplaceLane { lane } => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, i1) = v128_into_f32x4(builder, intrinsics, v1, i1); - let v2 = - apply_pending_canonicalization(builder, intrinsics, v2, i2).into_float_value(); - let i2 = i2.strip_pending(); + let push_pending_f32_nan_to_result = + i1.has_pending_f32_nan() && i2.has_pending_f32_nan(); + let (v1, v2) = if !push_pending_f32_nan_to_result { + ( + apply_pending_canonicalization( + builder, + intrinsics, + v1.as_basic_value_enum(), + i1, + ) + .into_vector_value(), + apply_pending_canonicalization( + builder, + intrinsics, + v2.as_basic_value_enum(), + i2, + ) + .into_float_value(), + ) + } else { + (v1, v2.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_extra(res, i1 & i2 & ExtraInfo::arithmetic_f32()); + let info = if push_pending_f32_nan_to_result { + ExtraInfo::pending_f32_nan() + } else { + i1.strip_pending() & i2.strip_pending() + }; + state.push1_extra(res, info); } Operator::F64x2ReplaceLane { lane } => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, i1) = v128_into_f64x2(builder, intrinsics, v1, i1); - let v2 = - apply_pending_canonicalization(builder, intrinsics, v2, i2).into_float_value(); - let i2 = i2.strip_pending(); + let push_pending_f64_nan_to_result = + i1.has_pending_f64_nan() && i2.has_pending_f64_nan(); + let (v1, v2) = if !push_pending_f64_nan_to_result { + ( + apply_pending_canonicalization( + builder, + intrinsics, + v1.as_basic_value_enum(), + i1, + ) + .into_vector_value(), + apply_pending_canonicalization( + builder, + intrinsics, + v2.as_basic_value_enum(), + i2, + ) + .into_float_value(), + ) + } else { + (v1, v2.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_extra(res, i1 & i2 & ExtraInfo::arithmetic_f64()); + let info = if push_pending_f64_nan_to_result { + ExtraInfo::pending_f64_nan() + } else { + i1.strip_pending() & i2.strip_pending() + }; + state.push1_extra(res, info); } Operator::V8x16Swizzle => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; diff --git a/lib/llvm-backend/src/state.rs b/lib/llvm-backend/src/state.rs index 82dbdbcf415..254b9b34442 100644 --- a/lib/llvm-backend/src/state.rs +++ b/lib/llvm-backend/src/state.rs @@ -159,8 +159,16 @@ impl BitAnd for ExtraInfo { type Output = Self; fn bitand(self, other: Self) -> Self { // Pending canonicalizations are not safe to discard, or even reorder. - assert!(self.has_pending_f32_nan() == other.has_pending_f32_nan()); - assert!(self.has_pending_f64_nan() == other.has_pending_f64_nan()); + assert!( + self.has_pending_f32_nan() == other.has_pending_f32_nan() + || self.is_arithmetic_f32() + || other.is_arithmetic_f32() + ); + assert!( + self.has_pending_f64_nan() == other.has_pending_f64_nan() + || self.is_arithmetic_f64() + || other.is_arithmetic_f64() + ); let info = match ( self.is_arithmetic_f32() && other.is_arithmetic_f32(), self.is_arithmetic_f64() && other.is_arithmetic_f64(), From fa576093c276a6b89750d017586d488f718a7bf0 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Wed, 6 Nov 2019 23:15:49 -0800 Subject: [PATCH 270/342] Fix ExtraInfo on F32Add and similar. We want to ignore the incoming pending NaN state (since the pending will propagate to the output if there was one on the input), and we want to add a new pending NaN state if we can (that is to say, if it isn't cancelled out by both inputs having arithmetic state). Do this by discarding the pending states on the inputs, intersecting them (to keep only the arithmetic state), then union in a pending nan state (which might do nothing, if it's arithmetic). If the above sounds confusing, keep in mind that when a value is arithmetic, the act of performing the "NaN canonicalization" is a no-op. Thus, being arithmetic cancels out pending NaN states. --- lib/llvm-backend/src/code.rs | 84 ++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 36 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 392f931e299..3ecad44e7d5 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -2907,110 +2907,122 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Operator::F32Add => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let i1 = i1 | ExtraInfo::pending_f32_nan(); - let i2 = i2 | ExtraInfo::pending_f32_nan(); let res = builder.build_float_add(v1, v2, &state.var_name()); - state.push1_extra(res, i1 & i2); + state.push1_extra( + res, + (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f32_nan(), + ); } Operator::F64Add => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let i1 = i1 | ExtraInfo::pending_f64_nan(); - let i2 = i2 | ExtraInfo::pending_f64_nan(); let res = builder.build_float_add(v1, v2, &state.var_name()); - state.push1_extra(res, i1 & i2); + state.push1_extra( + res, + (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f64_nan(), + ); } Operator::F32x4Add => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, i1) = v128_into_f32x4(builder, intrinsics, v1, i1); let (v2, i2) = v128_into_f32x4(builder, intrinsics, v2, i2); - let i1 = i1 | ExtraInfo::pending_f32_nan(); - let i2 = i2 | ExtraInfo::pending_f32_nan(); let res = builder.build_float_add(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1_extra(res, i1 & i2); + state.push1_extra( + res, + (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f32_nan(), + ); } Operator::F64x2Add => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, i1) = v128_into_f64x2(builder, intrinsics, v1, i1); let (v2, i2) = v128_into_f64x2(builder, intrinsics, v2, i2); - let i1 = i1 | ExtraInfo::pending_f64_nan(); - let i2 = i2 | ExtraInfo::pending_f64_nan(); let res = builder.build_float_add(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1_extra(res, i1 & i2); + state.push1_extra( + res, + (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f64_nan(), + ); } Operator::F32Sub => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let i1 = i1 | ExtraInfo::pending_f32_nan(); - let i2 = i2 | ExtraInfo::pending_f32_nan(); let res = builder.build_float_sub(v1, v2, &state.var_name()); - state.push1_extra(res, i1 & i2); + state.push1_extra( + res, + (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f32_nan(), + ); } Operator::F64Sub => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let i1 = i1 | ExtraInfo::pending_f64_nan(); - let i2 = i2 | ExtraInfo::pending_f64_nan(); let res = builder.build_float_sub(v1, v2, &state.var_name()); - state.push1_extra(res, i1 & i2); + state.push1_extra( + res, + (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f64_nan(), + ); } Operator::F32x4Sub => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, i1) = v128_into_f32x4(builder, intrinsics, v1, i1); let (v2, i2) = v128_into_f32x4(builder, intrinsics, v2, i2); - let i1 = i1 | ExtraInfo::pending_f32_nan(); - let i2 = i2 | ExtraInfo::pending_f32_nan(); let res = builder.build_float_sub(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1_extra(res, i1 & i2); + state.push1_extra( + res, + (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f32_nan(), + ); } Operator::F64x2Sub => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, i1) = v128_into_f64x2(builder, intrinsics, v1, i1); let (v2, i2) = v128_into_f64x2(builder, intrinsics, v2, i2); - let i1 = i1 | ExtraInfo::pending_f64_nan(); - let i2 = i2 | ExtraInfo::pending_f64_nan(); let res = builder.build_float_sub(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1_extra(res, i1 & i2); + state.push1_extra( + res, + (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f64_nan(), + ); } Operator::F32Mul => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let i1 = i1 | ExtraInfo::pending_f32_nan(); - let i2 = i2 | ExtraInfo::pending_f32_nan(); let res = builder.build_float_mul(v1, v2, &state.var_name()); - state.push1_extra(res, i1 & i2); + state.push1_extra( + res, + (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f32_nan(), + ); } Operator::F64Mul => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let i1 = i1 | ExtraInfo::pending_f64_nan(); - let i2 = i2 | ExtraInfo::pending_f64_nan(); let res = builder.build_float_mul(v1, v2, &state.var_name()); - state.push1_extra(res, i1 & i2); + state.push1_extra( + res, + (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f64_nan(), + ); } Operator::F32x4Mul => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, i1) = v128_into_f32x4(builder, intrinsics, v1, i1); let (v2, i2) = v128_into_f32x4(builder, intrinsics, v2, i2); - let i1 = i1 | ExtraInfo::pending_f32_nan(); - let i2 = i2 | ExtraInfo::pending_f32_nan(); let res = builder.build_float_mul(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1_extra(res, i1 & i2); + state.push1_extra( + res, + (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f32_nan(), + ); } Operator::F64x2Mul => { let ((v1, i1), (v2, i2)) = state.pop2_extra()?; let (v1, i1) = v128_into_f64x2(builder, intrinsics, v1, i1); let (v2, i2) = v128_into_f64x2(builder, intrinsics, v2, i2); - let i1 = i1 | ExtraInfo::pending_f64_nan(); - let i2 = i2 | ExtraInfo::pending_f64_nan(); let res = builder.build_float_mul(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1_extra(res, i1 & i2); + state.push1_extra( + res, + (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f64_nan(), + ); } Operator::F32Div => { let (v1, v2) = state.pop2()?; From d1ce8ee20d67d5a44bcdb169c368f66678f10240 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 7 Nov 2019 10:57:10 -0800 Subject: [PATCH 271/342] Give that panic! a message. Also, make it an unreachable!. --- lib/llvm-backend/src/state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/llvm-backend/src/state.rs b/lib/llvm-backend/src/state.rs index 254b9b34442..357d83d1f00 100644 --- a/lib/llvm-backend/src/state.rs +++ b/lib/llvm-backend/src/state.rs @@ -182,7 +182,7 @@ impl BitAnd for ExtraInfo { (false, false) => info, (true, false) => info | ExtraInfo::pending_f32_nan(), (false, true) => info | ExtraInfo::pending_f64_nan(), - (true, true) => panic!(""), + (true, true) => unreachable!("Can't form ExtraInfo with two pending canonicalizations"), }; info } From d3fabe576b1ab9f5167acf885895ad46f613e681 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 7 Nov 2019 10:59:54 -0800 Subject: [PATCH 272/342] Add changelog entry. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5df0b8ae3ab..30af3c6eb78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ Special thanks to [@newpavlov](https://github.com/newpavlov) and [@Maxgy](https: - [#939](https://github.com/wasmerio/wasmer/pull/939) Fix bug causing attempts to append to files with WASI to delete the contents of the file - [#940](https://github.com/wasmerio/wasmer/pull/940) Update supported Rust version to 1.38+ - [#923](https://github.com/wasmerio/wasmer/pull/923) Fix memory leak in the C API caused by an incorrect cast in `wasmer_trampoline_buffer_destroy` +- [#934](https://github.com/wasmerio/wasmer/pull/934) Simplify float expressions in the LLVM backend. - [#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 ff73c5d71b441c906f13faa8fa8ecc5ba2d18d2f Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 26 Nov 2019 12:15:26 -0800 Subject: [PATCH 273/342] Address review feedback from Mark. Fix a bug in Operator::Select and add a comment to explain the intention. Use derived default for ExtraInfo. Make ExtraInfo associated functions const. Turn two asserts into debug_asserts. --- CHANGELOG.md | 2 +- lib/llvm-backend/src/code.rs | 6 +++++- lib/llvm-backend/src/state.rs | 38 +++++++++++++++++++---------------- 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30af3c6eb78..aafd7885b72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - [#990](https://github.com/wasmerio/wasmer/pull/990) Default wasmer CLI to `run`. Wasmer will now attempt to parse unrecognized command line options as if they were applied to the run command: `wasmer mywasm.wasm --dir=.` now works! - [#987](https://github.com/wasmerio/wasmer/pull/987) Fix `runtime-c-api` header files when compiled by gnuc. - [#957](https://github.com/wasmerio/wasmer/pull/957) Change the meaning of `wasmer_wasi::is_wasi_module` to detect any type of WASI module, add support for new wasi snapshot_preview1 +- [#934](https://github.com/wasmerio/wasmer/pull/934) Simplify float expressions in the LLVM backend. ## 0.10.2 - 2019-11-18 @@ -36,7 +37,6 @@ Special thanks to [@newpavlov](https://github.com/newpavlov) and [@Maxgy](https: - [#939](https://github.com/wasmerio/wasmer/pull/939) Fix bug causing attempts to append to files with WASI to delete the contents of the file - [#940](https://github.com/wasmerio/wasmer/pull/940) Update supported Rust version to 1.38+ - [#923](https://github.com/wasmerio/wasmer/pull/923) Fix memory leak in the C API caused by an incorrect cast in `wasmer_trampoline_buffer_destroy` -- [#934](https://github.com/wasmerio/wasmer/pull/934) Simplify float expressions in the LLVM backend. - [#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 diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 3ecad44e7d5..d60ec5aea95 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -1740,7 +1740,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { // We don't bother canonicalizing 'cond' here because we only // compare it to zero, and that's invariant under // canonicalization. - let (v1, v2) = if i1.has_pending_f32_nan() != i1.has_pending_f32_nan() + + // 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() || i1.has_pending_f64_nan() != i2.has_pending_f64_nan() { ( diff --git a/lib/llvm-backend/src/state.rs b/lib/llvm-backend/src/state.rs index 357d83d1f00..b13b3c358ec 100644 --- a/lib/llvm-backend/src/state.rs +++ b/lib/llvm-backend/src/state.rs @@ -68,7 +68,7 @@ impl ControlFrame { } } -#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)] +#[derive(Debug, Default, Eq, PartialEq, Copy, Clone, Hash)] pub struct ExtraInfo { state: u8, } @@ -76,61 +76,65 @@ impl ExtraInfo { // This value 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. - pub fn pending_f32_nan() -> ExtraInfo { + // + // When applied to a 64-bit value, this flag has no meaning and must be + // ignored. It may be set in such cases to allow for common handling of + // 32 and 64-bit operations. + pub const fn pending_f32_nan() -> ExtraInfo { ExtraInfo { state: 1 } } // This value 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. - pub fn pending_f64_nan() -> ExtraInfo { + // + // When applied to a 32-bit value, this flag has no meaning and must be + // ignored. It may be set in such cases to allow for common handling of + // 32 and 64-bit operations. + pub const fn pending_f64_nan() -> ExtraInfo { ExtraInfo { state: 2 } } // This value either does not contain a 32-bit NaN, or it contains an // arithmetic NaN. In SIMD, applies to all 4 lanes. - pub fn arithmetic_f32() -> ExtraInfo { + pub const fn arithmetic_f32() -> ExtraInfo { ExtraInfo { state: 4 } } // This value either does not contain a 64-bit NaN, or it contains an // arithmetic NaN. In SIMD, applies to both lanes. - pub fn arithmetic_f64() -> ExtraInfo { + pub const fn arithmetic_f64() -> ExtraInfo { ExtraInfo { state: 8 } } - pub fn has_pending_f32_nan(&self) -> bool { + pub const fn has_pending_f32_nan(&self) -> bool { self.state & ExtraInfo::pending_f32_nan().state != 0 } - pub fn has_pending_f64_nan(&self) -> bool { + pub const fn has_pending_f64_nan(&self) -> bool { self.state & ExtraInfo::pending_f64_nan().state != 0 } - pub fn is_arithmetic_f32(&self) -> bool { + pub const fn is_arithmetic_f32(&self) -> bool { self.state & ExtraInfo::arithmetic_f32().state != 0 } - pub fn is_arithmetic_f64(&self) -> bool { + pub const fn is_arithmetic_f64(&self) -> bool { self.state & ExtraInfo::arithmetic_f64().state != 0 } - pub fn strip_pending(&self) -> ExtraInfo { + pub const fn strip_pending(&self) -> ExtraInfo { ExtraInfo { state: self.state & !(ExtraInfo::pending_f32_nan().state | ExtraInfo::pending_f64_nan().state), } } } -impl Default for ExtraInfo { - fn default() -> Self { - ExtraInfo { state: 0 } - } -} + // Union two ExtraInfos. impl BitOr for ExtraInfo { type Output = Self; fn bitor(self, other: Self) -> Self { - assert!(!(self.has_pending_f32_nan() && other.has_pending_f64_nan())); - assert!(!(self.has_pending_f64_nan() && other.has_pending_f32_nan())); + debug_assert!(!(self.has_pending_f32_nan() && other.has_pending_f64_nan())); + debug_assert!(!(self.has_pending_f64_nan() && other.has_pending_f32_nan())); ExtraInfo { state: if self.is_arithmetic_f32() || other.is_arithmetic_f32() { ExtraInfo::arithmetic_f32().state From 5a49fe76df89a0e46583bd524b252744084ea083 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 26 Nov 2019 16:43:17 -0800 Subject: [PATCH 274/342] Turn a few more assert!s that should never fire into debug_assert!s. These are here to protect against errors when refactoring more than anything else. --- lib/llvm-backend/src/code.rs | 4 ++-- lib/llvm-backend/src/state.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index d60ec5aea95..c3da185bef1 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -1764,11 +1764,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let info = { let mut info = i1.strip_pending() & i2.strip_pending(); if i1.has_pending_f32_nan() { - assert!(i2.has_pending_f32_nan()); + debug_assert!(i2.has_pending_f32_nan()); info |= ExtraInfo::pending_f32_nan(); } if i1.has_pending_f64_nan() { - assert!(i2.has_pending_f64_nan()); + debug_assert!(i2.has_pending_f64_nan()); info |= ExtraInfo::pending_f64_nan(); } info diff --git a/lib/llvm-backend/src/state.rs b/lib/llvm-backend/src/state.rs index b13b3c358ec..4b374f1da11 100644 --- a/lib/llvm-backend/src/state.rs +++ b/lib/llvm-backend/src/state.rs @@ -163,12 +163,12 @@ impl BitAnd for ExtraInfo { type Output = Self; fn bitand(self, other: Self) -> Self { // Pending canonicalizations are not safe to discard, or even reorder. - assert!( + debug_assert!( self.has_pending_f32_nan() == other.has_pending_f32_nan() || self.is_arithmetic_f32() || other.is_arithmetic_f32() ); - assert!( + debug_assert!( self.has_pending_f64_nan() == other.has_pending_f64_nan() || self.is_arithmetic_f64() || other.is_arithmetic_f64() From 31a77b0eb71bd943b9a45ab3f4924ab80eb5ae3b Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 4 Nov 2019 18:12:32 -0800 Subject: [PATCH 275/342] Fix llvm backend to work with latest inkwell. cargo update to pick up latest inkwell branch commit. Add lifetime annotations to Module which now takes a lifetime, and more lifetime annotations across intrinsics.rs. Add <'ctx> to missing places in CtxType and Intrinsics. Remove it from reference bindings. Use ManuallyDrop to ensure that context's members are dropped before the Context. Co-authored-by: Mark McCaskey --- Cargo.lock | 1147 +++++++++++++++++++++++---- lib/llvm-backend/Cargo.toml | 4 +- lib/llvm-backend/src/code.rs | 564 ++++++------- lib/llvm-backend/src/intrinsics.rs | 383 ++++----- lib/llvm-backend/src/lib.rs | 4 +- lib/llvm-backend/src/state.rs | 75 +- lib/llvm-backend/src/trampolines.rs | 22 +- 7 files changed, 1549 insertions(+), 650 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c92d5ceb1c3..fc0b1493c14 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,10 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "adler32" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "aho-corasick" version = "0.7.6" @@ -40,6 +45,34 @@ name = "autocfg" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "backtrace" +version = "0.3.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace-sys 0.1.32 (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)", + "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "base64" +version = "0.10.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 = "bincode" version = "1.2.0" @@ -47,7 +80,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.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -73,7 +106,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.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -81,6 +114,16 @@ name = "byteorder" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bytes" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "c2-chacha" version = "0.2.3" @@ -91,18 +134,21 @@ dependencies = [ [[package]] name = "cargo_toml" -version = "0.6.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "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)", + "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)", + "toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cast" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "cbindgen" @@ -113,8 +159,8 @@ 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.102 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.8 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -165,6 +211,46 @@ name = "constant_time_eq" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cookie" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cookie_store" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "publicsuffix 1.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "core-foundation" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "core-foundation-sys" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "cranelift-bforest" version = "0.44.0" @@ -218,28 +304,36 @@ dependencies = [ "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crc32fast" +version = "1.2.0" +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)", +] + [[package]] name = "criterion" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "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.1 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.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)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.10 (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)", "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.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)", + "rayon 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.6.1 (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)", + "serde_json 1.0.42 (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)", ] @@ -250,8 +344,8 @@ version = "0.3.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)", - "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -284,6 +378,14 @@ dependencies = [ "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-queue" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-utils" version = "0.6.6" @@ -312,7 +414,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.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -340,9 +442,14 @@ dependencies = [ "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "dtoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "dynasm" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -356,7 +463,7 @@ dependencies = [ [[package]] name = "dynasmrt" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -369,12 +476,11 @@ version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "enum-methods" -version = "0.0.8" +name = "encoding_rs" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -382,7 +488,7 @@ name = "erased-serde" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 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)", ] [[package]] @@ -404,11 +510,20 @@ dependencies = [ "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "error-chain" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "failure" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -420,14 +535,71 @@ 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.8 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "flate2" +version = "1.0.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)", + "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fnv" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fuchsia-cprng" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-cpupool" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "gcc" version = "0.3.55" @@ -435,11 +607,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "generational-arena" -version = "0.2.4" +version = "0.2.6" 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.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -490,6 +662,23 @@ dependencies = [ "scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "h2" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 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)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "heck" version = "0.3.1" @@ -511,37 +700,125 @@ name = "hex" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "http" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "http-body" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "httparse" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "hyper" +version = "0.12.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", + "http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hyper-tls" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "idna" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "idna" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "indexmap" 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.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (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#bd0d09a8041dc2217f698cd3631b6d4d4c0e696b" +source = "git+https://github.com/TheDan64/inkwell?rev=781620e9fa30e51a6e03bd0d49b5f5bb7a782520#781620e9fa30e51a6e03bd0d49b5f5bb7a782520" 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)", - "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)", + "inkwell_internals 0.1.0 (git+https://github.com/TheDan64/inkwell?rev=781620e9fa30e51a6e03bd0d49b5f5bb7a782520)", "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)", + "once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "inkwell_internal_macros" +name = "inkwell_internals" version = "0.1.0" -source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#bd0d09a8041dc2217f698cd3631b6d4d4c0e696b" +source = "git+https://github.com/TheDan64/inkwell?rev=781620e9fa30e51a6e03bd0d49b5f5bb7a782520#781620e9fa30e51a6e03bd0d49b5f5bb7a782520" dependencies = [ - "cargo_toml 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_toml 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", + "reqwest 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -565,9 +842,17 @@ dependencies = [ "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itertools" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -615,7 +900,7 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -629,6 +914,11 @@ dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "maybe-uninit" version = "2.0.0" @@ -664,6 +954,83 @@ dependencies = [ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "mime" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "mime_guess" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miniz_oxide" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "mio" +version = "0.6.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (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)", + "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miow" +version = "0.2.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)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "native-tls" +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)", + "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)", + "openssl 0.10.26 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.53 (registry+https://github.com/rust-lang/crates.io-index)", + "schannel 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "net2" +version = "0.2.33" +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)", + "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)", +] + [[package]] name = "nix" version = "0.15.0" @@ -678,7 +1045,7 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -686,13 +1053,48 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "once_cell" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "openssl" +version = "0.10.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.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)", + "openssl-sys 0.9.53 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "openssl-probe" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "openssl-sys" +version = "0.9.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "owning_ref" version = "0.4.0" @@ -715,7 +1117,7 @@ dependencies = [ name = "parallel" version = "0.1.0" dependencies = [ - "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.2.1 (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.11.0", "wasmer-runtime-core 0.11.0", @@ -734,7 +1136,7 @@ name = "parking_lot" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lock_api 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -753,6 +1155,21 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "percent-encoding" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pkg-config" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "plain" version = "0.2.3" @@ -794,9 +1211,16 @@ dependencies = [ ] [[package]] -name = "quote" -version = "0.3.15" +name = "publicsuffix" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.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)", + "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "quote" @@ -814,6 +1238,24 @@ dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (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.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand" version = "0.7.2" @@ -826,6 +1268,15 @@ dependencies = [ "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_chacha" version = "0.2.1" @@ -856,6 +1307,14 @@ dependencies = [ "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_hc" version = "0.2.0" @@ -864,6 +1323,24 @@ dependencies = [ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "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)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_os" version = "0.1.3" @@ -877,6 +1354,23 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_xoshiro" version = "0.1.0" @@ -898,24 +1392,24 @@ dependencies = [ [[package]] name = "rayon" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.7.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)", + "rayon-core 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon-core" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -963,6 +1457,44 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "reqwest" +version = "0.9.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "encoding_rs 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rustc_version" version = "0.2.3" @@ -984,6 +1516,15 @@ dependencies = [ "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "schannel" +version = "0.1.16" +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)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "scopeguard" version = "1.0.0" @@ -1008,6 +1549,25 @@ dependencies = [ "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "security-framework" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "security-framework-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "semver" version = "0.9.0" @@ -1023,10 +1583,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.102" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1035,7 +1595,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.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1043,12 +1603,12 @@ name = "serde_bytes" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 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)", ] [[package]] name = "serde_derive" -version = "1.0.102" +version = "1.0.103" 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)", @@ -1058,14 +1618,30 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.41" +version = "1.0.42" 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.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_urlencoded" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "smallvec" version = "0.6.13" @@ -1074,11 +1650,24 @@ dependencies = [ "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "smallvec" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "stable_deref_trait" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "string" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "strsim" version = "0.8.0" @@ -1086,16 +1675,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "structopt" -version = "0.3.4" +version = "0.3.5" 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.4 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "structopt-derive" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1105,16 +1694,6 @@ dependencies = [ "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "syn" -version = "0.11.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "syn" version = "0.15.44" @@ -1135,17 +1714,9 @@ dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "synom" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "synstructure" -version = "0.12.2" +version = "0.12.3" 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)", @@ -1161,7 +1732,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" 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)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1208,16 +1779,131 @@ name = "tinytemplate" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "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)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "toml" -version = "0.4.10" +name = "tokio" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-buf" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-current-thread" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-executor" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-io" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-reactor" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (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)", + "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-sync 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-sync" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-tcp" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-threadpool" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (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)", + "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-timer" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1225,7 +1911,20 @@ name = "toml" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 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)", +] + +[[package]] +name = "try-lock" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "try_from" +version = "0.3.2" +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)", ] [[package]] @@ -1241,7 +1940,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.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "typetag-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1255,6 +1954,30 @@ dependencies = [ "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-segmentation" version = "1.6.0" @@ -1267,17 +1990,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-xid" -version = "0.0.4" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-xid" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "unicode-xid" -version = "0.2.0" +name = "url" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "url" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "uuid" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "vcpkg" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1285,6 +2036,16 @@ 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 = "version_check" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "void" version = "1.0.2" @@ -1295,9 +2056,9 @@ name = "wabt" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "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)", + "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)", + "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1321,6 +2082,16 @@ dependencies = [ "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "want" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "wasi" version = "0.7.0" @@ -1334,8 +2105,8 @@ 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.102 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.3.5 (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.11.0", @@ -1363,17 +2134,17 @@ dependencies = [ "cranelift-native 0.44.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)", - "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (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.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.103 (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)", "wasmer-runtime-core 0.11.0", "wasmer-win-exception-handler 0.11.0", - "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.39.3 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1399,7 +2170,7 @@ dependencies = [ "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.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.39.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1450,7 +2221,7 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.47 (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)", + "inkwell 0.1.0 (git+https://github.com/TheDan64/inkwell?rev=781620e9fa30e51a6e03bd0d49b5f5bb7a782520)", "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)", @@ -1460,7 +2231,7 @@ dependencies = [ "smallvec 0.6.13 (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.11.0", - "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.39.3 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1537,12 +2308,12 @@ 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.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (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.102 (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)", - "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.39.3 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1562,8 +2333,8 @@ name = "wasmer-singlepass-backend" version = "0.11.0" dependencies = [ "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)", + "dynasm 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "dynasmrt 0.5.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)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1589,11 +2360,11 @@ 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)", - "generational-arena 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "generational-arena 0.2.6 (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)", - "serde 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)", "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.11.0", @@ -1625,7 +2396,7 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.39.2" +version = "0.39.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1665,21 +2436,43 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "winreg" +version = "0.6.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)", +] + +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [metadata] +"checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" "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.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" +"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea" +"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" +"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "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.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b83b7baab1e671718d78204225800d6b170e648188ac7dc992e9d6bddf87d0c0" "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 bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "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 cargo_toml 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e7877b00aaf997d7ed66a81281d3a8b9f9da5361df05b72785b985349979a0f3" +"checksum cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" "checksum cbindgen 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9daec6140ab4dcd38c3dd57e580b59a621172a526ac79f1527af760a55afeafd" "checksum cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "aa87058dce70a3ff5621797f1506cb837edd02ac4c0ae642b4542dce802908b8" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" @@ -1687,145 +2480,221 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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" "checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" +"checksum cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5" +"checksum cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46750b3f362965f197996c4448e4a0935e791bf7d6631bfce9ee0af3d24c919c" +"checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d" +"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" "checksum cranelift-bforest 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fff04f4ad82c9704a22e753c6268cc6a89add76f094b837cefbba1c665411451" "checksum cranelift-codegen 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff4a221ec1b95df4b1d20a99fec4fe92a28bebf3a815f2eca72b26f9a627485" "checksum cranelift-codegen-meta 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd47f665e2ee8f177b97d1f5ce2bd70f54d3b793abb26d92942bfaa4a381fe9f" "checksum cranelift-codegen-shared 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05bb95945fd940bd5fc2616b063ce69e55de3d9449a32fa40f6bb99a927085bf" "checksum cranelift-entity 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e8753f15d9bde04988834705d437b6f6e4b4da0527968b8d40d7342262d43052" "checksum cranelift-native 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd16b58e95af9ee837218cf41e70306becc1fc7d7dada55dac42df5130a4a4ba" +"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0363053954f3e679645fc443321ca128b7b950a6fe288cf5f9335cc22ee58394" "checksum criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76f9212ddf2f4a9eb2d401635190600656a1f88a932ef53d06e7fa4c7e02fb8e" "checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca" "checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac" "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" +"checksum crossbeam-queue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dfd6515864a82d2f877b42813d4553292c6659498c9a2aa31bab5a15243c2700" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" "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.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.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8654f63488a94cd11feac2a609fdcdecd09e02fb582731f635783689fbb429f3" -"checksum dynasmrt 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b0046b083139885c38990f2fb9822d06f6c5902068d93a6ed9e56b63011b9932" +"checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e" +"checksum dynasm 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "42a814e1edeb85dd2a3c6fc0d6bf76d02ca5695d438c70ecee3d90774f3259c5" +"checksum dynasmrt 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8a393aaeb4441a48bcf47b5b6155971f82cc1eb77e22855403ccc0415ac8328d" "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 encoding_rs 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)" = "87240518927716f79692c2ed85bfe6e98196d18c6401ec75355760233a7e12e9" "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 error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9" "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 flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd6d6f4752952feb71363cffc9ebac9411b75b87c6ab6058c40c8900cf43c0f" +"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" +"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +"checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" +"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" -"checksum generational-arena 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fd04ad33021a0409d3f1afbfb89d9f02c10caee73c28f5ac197474dd53e7cf7c" +"checksum generational-arena 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "675c9623fbcdb4b402176db720bf5d95883a36303703ed1bd3a03482382f735a" "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" "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" "checksum goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "e3fa261d919c1ae9d1e4533c4a2f99e10938603c4208d56c05bec7a872b661b0" +"checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" +"checksum http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "d7e06e336150b178206af098a055e3621e8336027e2b4d126bda0bc64824baaf" +"checksum http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" +"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" +"checksum hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)" = "9dbe6ed1438e1f8ad955a4701e9a944938e9519f6888d12d8558b645e247d5f6" +"checksum hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3a800d6aa50af4b5850b2b0f659625ce9504df908e9733b635720483be26174f" +"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" "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 inkwell 0.1.0 (git+https://github.com/TheDan64/inkwell?rev=781620e9fa30e51a6e03bd0d49b5f5bb7a782520)" = "" +"checksum inkwell_internals 0.1.0 (git+https://github.com/TheDan64/inkwell?rev=781620e9fa30e51a6e03bd0d49b5f5bb7a782520)" = "" "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.1 (registry+https://github.com/rust-lang/crates.io-index)" = "87fa75c9dea7b07be3138c49abbb83fd4bea199b5cdc76f9804458edc5da0d6e" +"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +"checksum itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" "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.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 lock_api 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e57b3997725d2b60dbec1297f6c2e2957cc383db1cebd6be812163f969c7d586" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" "checksum md5 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e6bcd6433cff03a4bfc3d9834d504467db1f1cf6d0ea765d37d330249ed629d" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" "checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" +"checksum mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "dd1d63acd1b78403cc0c325605908475dd9b9a3acbf65ed8bcab97e27014afcf" +"checksum mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a0ed03949aef72dbdf3116a383d7b38b4768e6f960528cd6a6044aa9ed68599" +"checksum miniz_oxide 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6f3f74f726ae935c3f514300cc6773a0c9492abc5e972d42ba0c0ebb88757625" +"checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" +"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +"checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e" +"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229" -"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" -"checksum num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "155394f924cdddf08149da25bfb932d226b4a593ca7468b08191ff6335941af5" +"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4" +"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72" +"checksum once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "891f486f630e5c5a4916c7e16c4b24a53e78c860b646e9f8e005e4f16847bfed" +"checksum openssl 0.10.26 (registry+https://github.com/rust-lang/crates.io-index)" = "3a3cc5799d98e1088141b8e01ff760112bbd9f19d850c124500566ca6901a585" +"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" +"checksum openssl-sys 0.9.53 (registry+https://github.com/rust-lang/crates.io-index)" = "465d16ae7fc0e313318f7de5cecf57b2fbe7511fd213978b457e1c96ff46736f" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" "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 percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" +"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" "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.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 publicsuffix 1.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3bbaa49075179162b49acac1c6aa45fb4dafb5f13cf6794276d77bc7fd95757b" "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" +"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" +"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03b418169fb9c46533f326efd6eed2576699c44ca92d3052a066214a8d828929" "checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d" -"checksum rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123" -"checksum rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b" +"checksum rayon 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "43739f8831493b276363637423d3622d4bd6394ab6f0a9c4a552e208aeb7fddd" +"checksum rayon-core 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8bf17de6f23b05473c437eb958b9c850bfc8af0961fe17b4cc92d5a627b4791" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" "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 reqwest 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)" = "2c2064233e442ce85c77231ebd67d9eca395207dec2127fe0bbedde4bd29a650" +"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "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 schannel 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "87f550b06b6cba9c8b8be3ee73f391990116bf527450d2556e9b9ce263b9a021" "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" "checksum scroll_derive 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1aa96c45e7f5a91cb7fabe7b279f02fea7126239fc40b732316e8b6a2d0fcb" +"checksum security-framework 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8ef2429d7cefe5fd28bd1d2ed41c944547d4ff84776f5935b456da44593a16df" +"checksum security-framework-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e31493fc37615debb8c5090a7aeb4a9730bc61e77ab10b9af59f1a202284f895" "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.102 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4b39bd9b0b087684013a792c59e3e07a46a01d2322518d8a1104641a0b1be0" +"checksum serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "1217f97ab8e8904b57dd22eb61cde455fa7446a9c1cf43966066da047c1f3702" "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.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 serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "a8c6faef9a2e64b0064f48570289b4bf8823b7581f1d6157c1b52152306651d0" +"checksum serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)" = "1a3351dcbc1f067e2c92ab7c3c1f288ad1a4cffc470b5aaddb4c2e0a3ae80043" +"checksum serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a" +"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" +"checksum smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecf3b85f68e8abaa7555aa5abdb1153079387e60b718283d732f03897fcfc86" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" +"checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum structopt 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c167b61c7d4c126927f5346a4327ce20abf8a186b8041bbeb1ce49e5db49587b" -"checksum structopt-derive 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "519621841414165d2ad0d4c92be8f41844203f2b67e245f9345a5a12d40c69d7" -"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" +"checksum structopt 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "30b3a3e93f5ad553c38b3301c8a0a0cec829a36783f6a0c467fc4bf553a5f5bf" +"checksum structopt-derive 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea692d40005b3ceba90a9fe7a78fa8d4b82b0ce627eebbffc329aab850f3410e" "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" "checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92" -"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -"checksum synstructure 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "575be94ccb86e8da37efb894a87e2b660be299b41d8ef347f9d6d79fbe61b1ba" +"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" "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 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" "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 tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" +"checksum tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" +"checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443" +"checksum tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f27ee0e6db01c5f0b2973824547ce7e637b2ed79b891a9677b0de9bd532b6ac" +"checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926" +"checksum tokio-reactor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "c56391be9805bc80163151c0b9e5164ee64f4b0200962c346fea12773158f22d" +"checksum tokio-sync 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d06554cce1ae4a50f42fba8023918afa931413aded705b560e29600ccf7c6d76" +"checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" +"checksum tokio-threadpool 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "2bd2c6a3885302581f4401c82af70d792bb9df1700e7437b0aeb4ada94d5388c" +"checksum tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f2106812d500ed25a4f38235b9cae8f78a09edf43203e16e59c3b769a342a60e" "checksum toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01d1404644c8b12b16bfcffa4322403a91a451584daaaa7c28d3152e6cbc98cf" +"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" +"checksum try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b" "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" +"checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +"checksum unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b561e267b2326bb4cebfc0ef9e68355c7abe6c6f522aeac2f5bf95d56c59bdcf" "checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" -"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "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 url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" +"checksum url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75b414f6c464c879d7f9babf951f23bc3743fb7313c081b2e6ca719067ea9d61" +"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" +"checksum vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "33dd455d0f96e90a75803cfeb7f948768c08d70a6de9a8d2362461935698bf95" "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 version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" "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" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" +"checksum want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" "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.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5083b449454f7de0b15f131eee17de54b5a71dcb9adcf11df2b2f78fad0cd82" +"checksum wasmparser 0.39.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c702914acda5feeeffbc29e4d953e5b9ce79d8b98da4dbf18a77086e116c5470" "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 winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" +"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" diff --git a/lib/llvm-backend/Cargo.toml b/lib/llvm-backend/Cargo.toml index 2f5db92de99..b9fa7e6a720 100644 --- a/lib/llvm-backend/Cargo.toml +++ b/lib/llvm-backend/Cargo.toml @@ -18,8 +18,8 @@ libc = "0.2.60" byteorder = "1" [dependencies.inkwell] -git = "https://github.com/wasmerio/inkwell" -branch = "llvm8-0" +git = "https://github.com/TheDan64/inkwell" +rev = "781620e9fa30e51a6e03bd0d49b5f5bb7a782520" default-features = false features = ["llvm8-0", "target-x86"] diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index c3da185bef1..7f7e1e32f6b 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -23,6 +23,7 @@ use smallvec::SmallVec; use std::{ cell::RefCell, collections::HashMap, + mem::ManuallyDrop, rc::Rc, sync::{Arc, RwLock}, }; @@ -39,12 +40,12 @@ use wasmer_runtime_core::{ }; use wasmparser::{BinaryReaderError, MemoryImmediate, Operator, Type as WpType}; -fn func_sig_to_llvm( - context: &Context, - intrinsics: &Intrinsics, +fn func_sig_to_llvm<'ctx>( + context: &'ctx Context, + intrinsics: &Intrinsics<'ctx>, sig: &FuncSig, - type_to_llvm: fn(intrinsics: &Intrinsics, ty: Type) -> BasicTypeEnum, -) -> FunctionType { + type_to_llvm: fn(intrinsics: &Intrinsics<'ctx>, ty: Type) -> BasicTypeEnum<'ctx>, +) -> FunctionType<'ctx> { let user_param_types = sig.params().iter().map(|&ty| type_to_llvm(intrinsics, ty)); let param_types: Vec<_> = std::iter::once(intrinsics.ctx_ptr_ty.as_basic_type_enum()) @@ -67,7 +68,7 @@ fn func_sig_to_llvm( } } -fn type_to_llvm(intrinsics: &Intrinsics, ty: Type) -> BasicTypeEnum { +fn type_to_llvm<'ctx>(intrinsics: &Intrinsics<'ctx>, ty: Type) -> BasicTypeEnum<'ctx> { match ty { Type::I32 => intrinsics.i32_ty.as_basic_type_enum(), Type::I64 => intrinsics.i64_ty.as_basic_type_enum(), @@ -77,7 +78,7 @@ fn type_to_llvm(intrinsics: &Intrinsics, ty: Type) -> BasicTypeEnum { } } -fn type_to_llvm_int_only(intrinsics: &Intrinsics, ty: Type) -> BasicTypeEnum { +fn type_to_llvm_int_only<'ctx>(intrinsics: &Intrinsics<'ctx>, ty: Type) -> BasicTypeEnum<'ctx> { match ty { Type::I32 | Type::F32 => intrinsics.i32_ty.as_basic_type_enum(), Type::I64 | Type::F64 => intrinsics.i64_ty.as_basic_type_enum(), @@ -86,13 +87,13 @@ fn type_to_llvm_int_only(intrinsics: &Intrinsics, ty: Type) -> BasicTypeEnum { } // Create a vector where each lane contains the same value. -fn splat_vector( - builder: &Builder, - intrinsics: &Intrinsics, - value: BasicValueEnum, - vec_ty: VectorType, +fn splat_vector<'ctx>( + builder: &Builder<'ctx>, + intrinsics: &Intrinsics<'ctx>, + value: BasicValueEnum<'ctx>, + vec_ty: VectorType<'ctx>, name: &str, -) -> VectorValue { +) -> VectorValue<'ctx> { // Use insert_element to insert the element into an undef vector, then use // shuffle vector to copy that lane to all lanes. builder.build_shuffle_vector( @@ -106,18 +107,18 @@ fn splat_vector( // Convert floating point vector to integer and saturate when out of range. // TODO: generalize to non-vectors using FloatMathType, IntMathType, etc. for // https://github.com/WebAssembly/nontrapping-float-to-int-conversions/blob/master/proposals/nontrapping-float-to-int-conversion/Overview.md -fn trunc_sat( - builder: &Builder, - intrinsics: &Intrinsics, - fvec_ty: VectorType, - ivec_ty: VectorType, +fn trunc_sat<'ctx>( + builder: &Builder<'ctx>, + intrinsics: &Intrinsics<'ctx>, + fvec_ty: VectorType<'ctx>, + ivec_ty: VectorType<'ctx>, lower_bound: u64, // Exclusive (lowest representable value) upper_bound: u64, // Exclusive (greatest representable value) int_min_value: u64, int_max_value: u64, - value: IntValue, + value: IntValue<'ctx>, name: &str, -) -> IntValue { +) -> IntValue<'ctx> { // a) Compare vector with itself to identify NaN lanes. // b) Compare vector with splat of inttofp(upper_bound) to identify // lanes that need to saturate to max. @@ -225,11 +226,11 @@ fn trunc_sat( .into_int_value() } -fn trap_if_not_representable_as_int( - builder: &Builder, - intrinsics: &Intrinsics, - context: &Context, - function: &FunctionValue, +fn trap_if_not_representable_as_int<'ctx>( + builder: &Builder<'ctx>, + intrinsics: &Intrinsics<'ctx>, + context: &'ctx Context, + function: &FunctionValue<'ctx>, lower_bound: u64, // Inclusive (not a trapping value) upper_bound: u64, // Inclusive (not a trapping value) value: FloatValue, @@ -261,8 +262,8 @@ fn trap_if_not_representable_as_int( "out_of_bounds", ); - let failure_block = context.append_basic_block(function, "conversion_failure_block"); - let continue_block = context.append_basic_block(function, "conversion_success_block"); + let failure_block = context.append_basic_block(*function, "conversion_failure_block"); + let continue_block = context.append_basic_block(*function, "conversion_success_block"); builder.build_conditional_branch(out_of_bounds, &failure_block, &continue_block); builder.position_at_end(&failure_block); @@ -275,11 +276,11 @@ fn trap_if_not_representable_as_int( builder.position_at_end(&continue_block); } -fn trap_if_zero_or_overflow( - builder: &Builder, - intrinsics: &Intrinsics, - context: &Context, - function: &FunctionValue, +fn trap_if_zero_or_overflow<'ctx>( + builder: &Builder<'ctx>, + intrinsics: &Intrinsics<'ctx>, + context: &'ctx Context, + function: &FunctionValue<'ctx>, left: IntValue, right: IntValue, ) { @@ -326,8 +327,8 @@ fn trap_if_zero_or_overflow( .unwrap() .into_int_value(); - let shouldnt_trap_block = context.append_basic_block(function, "shouldnt_trap_block"); - let should_trap_block = context.append_basic_block(function, "should_trap_block"); + let shouldnt_trap_block = context.append_basic_block(*function, "shouldnt_trap_block"); + let should_trap_block = context.append_basic_block(*function, "should_trap_block"); builder.build_conditional_branch(should_trap, &should_trap_block, &shouldnt_trap_block); builder.position_at_end(&should_trap_block); builder.build_call( @@ -339,11 +340,11 @@ fn trap_if_zero_or_overflow( builder.position_at_end(&shouldnt_trap_block); } -fn trap_if_zero( - builder: &Builder, - intrinsics: &Intrinsics, - context: &Context, - function: &FunctionValue, +fn trap_if_zero<'ctx>( + builder: &Builder<'ctx>, + intrinsics: &Intrinsics<'ctx>, + context: &'ctx Context, + function: &FunctionValue<'ctx>, value: IntValue, ) { let int_type = value.get_type(); @@ -368,8 +369,8 @@ fn trap_if_zero( .unwrap() .into_int_value(); - let shouldnt_trap_block = context.append_basic_block(function, "shouldnt_trap_block"); - let should_trap_block = context.append_basic_block(function, "should_trap_block"); + let shouldnt_trap_block = context.append_basic_block(*function, "shouldnt_trap_block"); + let should_trap_block = context.append_basic_block(*function, "should_trap_block"); builder.build_conditional_branch(should_trap, &should_trap_block, &shouldnt_trap_block); builder.position_at_end(&should_trap_block); builder.build_call( @@ -381,13 +382,13 @@ fn trap_if_zero( builder.position_at_end(&shouldnt_trap_block); } -fn v128_into_int_vec( - builder: &Builder, - intrinsics: &Intrinsics, - value: BasicValueEnum, +fn v128_into_int_vec<'ctx>( + builder: &Builder<'ctx>, + intrinsics: &Intrinsics<'ctx>, + value: BasicValueEnum<'ctx>, info: ExtraInfo, - int_vec_ty: VectorType, -) -> (VectorValue, ExtraInfo) { + int_vec_ty: VectorType<'ctx>, +) -> (VectorValue<'ctx>, ExtraInfo) { let (value, info) = if info.has_pending_f32_nan() { let value = builder.build_bitcast(value, intrinsics.f32x4_ty, ""); ( @@ -411,50 +412,50 @@ fn v128_into_int_vec( ) } -fn v128_into_i8x16( - builder: &Builder, - intrinsics: &Intrinsics, - value: BasicValueEnum, +fn v128_into_i8x16<'ctx>( + builder: &Builder<'ctx>, + intrinsics: &Intrinsics<'ctx>, + value: BasicValueEnum<'ctx>, info: ExtraInfo, -) -> (VectorValue, ExtraInfo) { +) -> (VectorValue<'ctx>, ExtraInfo) { v128_into_int_vec(builder, intrinsics, value, info, intrinsics.i8x16_ty) } -fn v128_into_i16x8( - builder: &Builder, - intrinsics: &Intrinsics, - value: BasicValueEnum, +fn v128_into_i16x8<'ctx>( + builder: &Builder<'ctx>, + intrinsics: &Intrinsics<'ctx>, + value: BasicValueEnum<'ctx>, info: ExtraInfo, -) -> (VectorValue, ExtraInfo) { +) -> (VectorValue<'ctx>, ExtraInfo) { v128_into_int_vec(builder, intrinsics, value, info, intrinsics.i16x8_ty) } -fn v128_into_i32x4( - builder: &Builder, - intrinsics: &Intrinsics, - value: BasicValueEnum, +fn v128_into_i32x4<'ctx>( + builder: &Builder<'ctx>, + intrinsics: &Intrinsics<'ctx>, + value: BasicValueEnum<'ctx>, info: ExtraInfo, -) -> (VectorValue, ExtraInfo) { +) -> (VectorValue<'ctx>, ExtraInfo) { v128_into_int_vec(builder, intrinsics, value, info, intrinsics.i32x4_ty) } -fn v128_into_i64x2( - builder: &Builder, - intrinsics: &Intrinsics, - value: BasicValueEnum, +fn v128_into_i64x2<'ctx>( + builder: &Builder<'ctx>, + intrinsics: &Intrinsics<'ctx>, + value: BasicValueEnum<'ctx>, info: ExtraInfo, -) -> (VectorValue, ExtraInfo) { +) -> (VectorValue<'ctx>, ExtraInfo) { 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, +fn v128_into_f32x4<'ctx>( + builder: &Builder<'ctx>, + intrinsics: &Intrinsics<'ctx>, + value: BasicValueEnum<'ctx>, info: ExtraInfo, -) -> (VectorValue, ExtraInfo) { +) -> (VectorValue<'ctx>, ExtraInfo) { let (value, info) = if info.has_pending_f64_nan() { let value = builder.build_bitcast(value, intrinsics.f64x2_ty, ""); ( @@ -474,12 +475,12 @@ fn v128_into_f32x4( // 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, +fn v128_into_f64x2<'ctx>( + builder: &Builder<'ctx>, + intrinsics: &Intrinsics<'ctx>, + value: BasicValueEnum<'ctx>, info: ExtraInfo, -) -> (VectorValue, ExtraInfo) { +) -> (VectorValue<'ctx>, ExtraInfo) { let (value, info) = if info.has_pending_f32_nan() { let value = builder.build_bitcast(value, intrinsics.f32x4_ty, ""); ( @@ -497,12 +498,12 @@ fn v128_into_f64x2( ) } -fn apply_pending_canonicalization( - builder: &Builder, - intrinsics: &Intrinsics, - value: BasicValueEnum, +fn apply_pending_canonicalization<'ctx>( + builder: &Builder<'ctx>, + intrinsics: &Intrinsics<'ctx>, + value: BasicValueEnum<'ctx>, info: ExtraInfo, -) -> BasicValueEnum { +) -> BasicValueEnum<'ctx> { if info.has_pending_f32_nan() { if value.get_type().is_vector_type() || value.get_type() == intrinsics.i128_ty.as_basic_type_enum() @@ -531,11 +532,11 @@ fn apply_pending_canonicalization( } // Replaces any NaN with the canonical QNaN, otherwise leaves the value alone. -fn canonicalize_nans( - builder: &Builder, - intrinsics: &Intrinsics, - value: BasicValueEnum, -) -> BasicValueEnum { +fn canonicalize_nans<'ctx>( + builder: &Builder<'ctx>, + intrinsics: &Intrinsics<'ctx>, + value: BasicValueEnum<'ctx>, +) -> BasicValueEnum<'ctx> { let f_ty = value.get_type(); let canonicalized = if f_ty.is_vector_type() { let value = value.into_vector_value(); @@ -569,18 +570,18 @@ fn canonicalize_nans( canonicalized } -fn resolve_memory_ptr( - builder: &Builder, - intrinsics: &Intrinsics, - context: &Context, - module: Rc>, - function: &FunctionValue, - state: &mut State, - ctx: &mut CtxType, +fn resolve_memory_ptr<'ctx>( + builder: &Builder<'ctx>, + intrinsics: &Intrinsics<'ctx>, + context: &'ctx Context, + module: Rc>>, + function: &FunctionValue<'ctx>, + state: &mut State<'ctx>, + ctx: &mut CtxType<'static, 'ctx>, memarg: &MemoryImmediate, - ptr_ty: PointerType, + ptr_ty: PointerType<'ctx>, value_size: usize, -) -> Result { +) -> Result, BinaryReaderError> { // Look up the memory base (as pointer) and bounds (as unsigned integer). let memory_cache = ctx.memory(MemoryIndex::new(0), intrinsics, module.clone()); let (mem_base, mem_bound, minimum, _maximum) = match memory_cache { @@ -595,14 +596,14 @@ fn resolve_memory_ptr( .into_pointer_value(); let bounds = builder.build_load(ptr_to_bounds, "bounds").into_int_value(); tbaa_label( - module.clone(), + &module, intrinsics, "dynamic_memory_base", base.as_instruction_value().unwrap(), Some(0), ); tbaa_label( - module.clone(), + &module, intrinsics, "dynamic_memory_bounds", bounds.as_instruction_value().unwrap(), @@ -680,8 +681,8 @@ fn resolve_memory_ptr( .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"); + 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, @@ -704,16 +705,16 @@ fn resolve_memory_ptr( .into_pointer_value()) } -fn emit_stack_map( +fn emit_stack_map<'ctx>( _module_info: &ModuleInfo, - intrinsics: &Intrinsics, - builder: &Builder, + intrinsics: &Intrinsics<'ctx>, + builder: &Builder<'ctx>, local_function_id: usize, target: &mut StackmapRegistry, kind: StackmapEntryKind, locals: &[PointerValue], - state: &State, - _ctx: &mut CtxType, + state: &State<'ctx>, + _ctx: &mut CtxType<'_, 'ctx>, opcode_offset: usize, ) { let stackmap_id = target.entries.len(); @@ -757,9 +758,9 @@ fn emit_stack_map( }); } -fn finalize_opcode_stack_map( - intrinsics: &Intrinsics, - builder: &Builder, +fn finalize_opcode_stack_map<'ctx>( + intrinsics: &Intrinsics<'ctx>, + builder: &Builder<'ctx>, local_function_id: usize, target: &mut StackmapRegistry, kind: StackmapEntryKind, @@ -788,13 +789,13 @@ fn finalize_opcode_stack_map( }); } -fn trap_if_misaligned( - builder: &Builder, - intrinsics: &Intrinsics, - context: &Context, - function: &FunctionValue, +fn trap_if_misaligned<'ctx>( + builder: &Builder<'ctx>, + intrinsics: &Intrinsics<'ctx>, + context: &'ctx Context, + function: &FunctionValue<'ctx>, memarg: &MemoryImmediate, - ptr: PointerValue, + ptr: PointerValue<'ctx>, ) { let align = match memarg.flags & 3 { 0 => { @@ -826,8 +827,8 @@ fn trap_if_misaligned( .unwrap() .into_int_value(); - let continue_block = context.append_basic_block(function, "aligned_access_continue_block"); - let not_aligned_block = context.append_basic_block(function, "misaligned_trap_block"); + let continue_block = context.append_basic_block(*function, "aligned_access_continue_block"); + let not_aligned_block = context.append_basic_block(*function, "misaligned_trap_block"); builder.build_conditional_branch(aligned, &continue_block, ¬_aligned_block); builder.position_at_end(¬_aligned_block); @@ -861,45 +862,45 @@ pub unsafe extern "C" fn callback_trampoline( } } -pub struct LLVMModuleCodeGenerator { - context: Option, - builder: Option, - intrinsics: Option, - functions: Vec, - signatures: Map, +pub struct LLVMModuleCodeGenerator<'ctx> { + context: Option<&'ctx Context>, + builder: Option>, + intrinsics: Option>, + functions: Vec>, + signatures: Map>, signatures_raw: Map, function_signatures: Option>>, - llvm_functions: Rc>>, + llvm_functions: Rc>>>, func_import_count: usize, - personality_func: FunctionValue, - module: Rc>, + personality_func: ManuallyDrop>, + module: ManuallyDrop>>>, stackmaps: Rc>, track_state: bool, target_machine: TargetMachine, } -pub struct LLVMFunctionCodeGenerator { - context: Option, - builder: Option, - alloca_builder: Option, - intrinsics: Option, - state: State, - llvm_functions: Rc>>, - function: FunctionValue, +pub struct LLVMFunctionCodeGenerator<'ctx> { + context: Option<&'ctx Context>, + builder: Option>, + alloca_builder: Option>, + intrinsics: Option>, + state: State<'ctx>, + llvm_functions: Rc>>>, + function: FunctionValue<'ctx>, func_sig: FuncSig, - signatures: Map, - locals: Vec, // Contains params and locals + signatures: Map>, + locals: Vec>, // Contains params and locals num_params: usize, - ctx: Option>, + ctx: Option>, unreachable_depth: usize, stackmaps: Rc>, index: usize, opcode_offset: usize, track_state: bool, - module: Rc>, + module: Rc>>, } -impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { +impl<'ctx> FunctionCodeGenerator for LLVMFunctionCodeGenerator<'ctx> { fn feed_return(&mut self, _ty: WpType) -> Result<(), CodegenError> { Ok(()) } @@ -950,7 +951,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .context .as_ref() .unwrap() - .append_basic_block(&self.function, "start_of_code"); + .append_basic_block(self.function, "start_of_code"); let entry_end_inst = self .builder .as_ref() @@ -965,10 +966,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { cache_builder.position_before(&entry_end_inst); let module_info = unsafe { ::std::mem::transmute::<&ModuleInfo, &'static ModuleInfo>(module_info) }; - let function = unsafe { - ::std::mem::transmute::<&FunctionValue, &'static FunctionValue>(&self.function) - }; - let ctx = CtxType::new(module_info, function, cache_builder); + let ctx = CtxType::new(module_info, &self.function, cache_builder); self.ctx = Some(ctx); @@ -1045,7 +1043,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ctx.internal_field(idx, intrinsics, self.module.clone(), builder); let result = builder.build_load(field_ptr, "get_internal"); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "internal", result.as_instruction_value().unwrap(), @@ -1062,7 +1060,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let v = state.pop1()?; let store = builder.build_store(field_ptr, v); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "internal", store, @@ -1110,7 +1108,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { offset: -1isize as usize, })?; - let end_block = context.append_basic_block(&function, "end"); + let end_block = context.append_basic_block(function, "end"); builder.position_at_end(&end_block); let phis = if let Ok(wasmer_ty) = blocktype_to_type(ty) { @@ -1127,8 +1125,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.position_at_end(¤t_block); } Operator::Loop { ty } => { - let loop_body = context.append_basic_block(&function, "loop_body"); - let loop_next = context.append_basic_block(&function, "loop_outer"); + let loop_body = context.append_basic_block(function, "loop_body"); + let loop_next = context.append_basic_block(function, "loop_outer"); builder.build_unconditional_branch(&loop_body); @@ -1233,7 +1231,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { phi.add_incoming(&[(&value, ¤t_block)]); } - let else_block = context.append_basic_block(&function, "else"); + let else_block = context.append_basic_block(function, "else"); let cond_value = builder.build_int_compare( IntPredicate::NE, @@ -1299,9 +1297,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { message: "not currently in a block", offset: -1isize as usize, })?; - let if_then_block = context.append_basic_block(&function, "if_then"); - let if_else_block = context.append_basic_block(&function, "if_else"); - let end_block = context.append_basic_block(&function, "if_end"); + let if_then_block = context.append_basic_block(function, "if_then"); + let if_else_block = context.append_basic_block(function, "if_else"); + let end_block = context.append_basic_block(function, "if_end"); let end_phis = { builder.position_at_end(&end_block); @@ -1656,7 +1654,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let pointer_value = locals[local_index as usize]; let v = builder.build_load(pointer_value, &state.var_name()); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "local", v.as_instruction_value().unwrap(), @@ -1669,26 +1667,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); - tbaa_label( - self.module.clone(), - intrinsics, - "local", - store, - Some(local_index), - ); + tbaa_label(&self.module, 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); - tbaa_label( - self.module.clone(), - intrinsics, - "local", - store, - Some(local_index), - ); + tbaa_label(&self.module, intrinsics, "local", store, Some(local_index)); } Operator::GetGlobal { global_index } => { @@ -1701,7 +1687,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { GlobalCache::Mut { ptr_to_value } => { let value = builder.build_load(ptr_to_value, "global_value"); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "global", value.as_instruction_value().unwrap(), @@ -1720,7 +1706,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { GlobalCache::Mut { ptr_to_value } => { let store = builder.build_store(ptr_to_value, value); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "global", store, @@ -1994,9 +1980,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .into_int_value(); let in_bounds_continue_block = - context.append_basic_block(&function, "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"); + context.append_basic_block(function, "not_in_bounds_block"); builder.build_conditional_branch( index_in_bounds, &in_bounds_continue_block, @@ -2035,9 +2021,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .unwrap() .into_int_value(); - let continue_block = context.append_basic_block(&function, "continue_block"); + let continue_block = context.append_basic_block(function, "continue_block"); let sigindices_notequal_block = - context.append_basic_block(&function, "sigindices_notequal_block"); + context.append_basic_block(function, "sigindices_notequal_block"); builder.build_conditional_branch( sigindices_equal, &continue_block, @@ -4760,7 +4746,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .set_alignment(1) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", result.as_instruction_value().unwrap(), @@ -4788,7 +4774,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .set_alignment(1) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", result.as_instruction_value().unwrap(), @@ -4816,7 +4802,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .set_alignment(1) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", result.as_instruction_value().unwrap(), @@ -4844,7 +4830,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .set_alignment(1) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", result.as_instruction_value().unwrap(), @@ -4872,7 +4858,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .set_alignment(1) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", result.as_instruction_value().unwrap(), @@ -4897,7 +4883,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { )?; let store = builder.build_store(effective_address, value); store.set_alignment(1).unwrap(); - tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); + tbaa_label(&self.module, intrinsics, "memory", store, Some(0)); } Operator::I64Store { ref memarg } => { let value = state.pop1()?; @@ -4915,7 +4901,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { )?; let store = builder.build_store(effective_address, value); store.set_alignment(1).unwrap(); - tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); + tbaa_label(&self.module, intrinsics, "memory", store, Some(0)); } Operator::F32Store { ref memarg } => { let (v, i) = state.pop1_extra()?; @@ -4934,7 +4920,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { )?; let store = builder.build_store(effective_address, v); store.set_alignment(1).unwrap(); - tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); + tbaa_label(&self.module, intrinsics, "memory", store, Some(0)); } Operator::F64Store { ref memarg } => { let (v, i) = state.pop1_extra()?; @@ -4953,7 +4939,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { )?; let store = builder.build_store(effective_address, v); store.set_alignment(1).unwrap(); - tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); + tbaa_label(&self.module, intrinsics, "memory", store, Some(0)); } Operator::V128Store { ref memarg } => { let (v, i) = state.pop1_extra()?; @@ -4972,7 +4958,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { )?; let store = builder.build_store(effective_address, v); store.set_alignment(1).unwrap(); - tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); + tbaa_label(&self.module, intrinsics, "memory", store, Some(0)); } Operator::I32Load8S { ref memarg } => { let effective_address = resolve_memory_ptr( @@ -4994,7 +4980,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .set_alignment(1) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", narrow_result.as_instruction_value().unwrap(), @@ -5027,7 +5013,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .set_alignment(1) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", narrow_result.as_instruction_value().unwrap(), @@ -5062,7 +5048,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .set_alignment(1) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", narrow_result.as_instruction_value().unwrap(), @@ -5094,7 +5080,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .set_alignment(1) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", narrow_result.as_instruction_value().unwrap(), @@ -5124,7 +5110,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .set_alignment(1) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", narrow_result.as_instruction_value().unwrap(), @@ -5158,7 +5144,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .set_alignment(1) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", narrow_result.as_instruction_value().unwrap(), @@ -5191,7 +5177,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .set_alignment(1) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", narrow_result.as_instruction_value().unwrap(), @@ -5224,7 +5210,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .set_alignment(1) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", narrow_result.as_instruction_value().unwrap(), @@ -5257,7 +5243,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .set_alignment(1) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", narrow_result.as_instruction_value().unwrap(), @@ -5290,7 +5276,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .set_alignment(1) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", narrow_result.as_instruction_value().unwrap(), @@ -5322,7 +5308,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.build_int_truncate(value, intrinsics.i8_ty, &state.var_name()); let store = builder.build_store(effective_address, narrow_value); store.set_alignment(1).unwrap(); - tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); + tbaa_label(&self.module, intrinsics, "memory", store, Some(0)); } Operator::I32Store16 { ref memarg } | Operator::I64Store16 { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -5342,7 +5328,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.build_int_truncate(value, intrinsics.i16_ty, &state.var_name()); let store = builder.build_store(effective_address, narrow_value); store.set_alignment(1).unwrap(); - tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); + tbaa_label(&self.module, intrinsics, "memory", store, Some(0)); } Operator::I64Store32 { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -5362,7 +5348,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.build_int_truncate(value, intrinsics.i32_ty, &state.var_name()); let store = builder.build_store(effective_address, narrow_value); store.set_alignment(1).unwrap(); - tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); + tbaa_label(&self.module, intrinsics, "memory", store, Some(0)); } Operator::I8x16Neg => { let (v, i) = state.pop1_extra()?; @@ -5731,7 +5717,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .set_alignment(1) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", elem.as_instruction_value().unwrap(), @@ -5766,7 +5752,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .set_alignment(1) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", elem.as_instruction_value().unwrap(), @@ -5801,7 +5787,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .set_alignment(1) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", elem.as_instruction_value().unwrap(), @@ -5836,7 +5822,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .set_alignment(1) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", elem.as_instruction_value().unwrap(), @@ -5887,7 +5873,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(4).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - tbaa_label(self.module.clone(), intrinsics, "memory", load, Some(0)); + tbaa_label(&self.module, intrinsics, "memory", load, Some(0)); state.push1(result); } Operator::I64AtomicLoad { ref memarg } => { @@ -5916,7 +5902,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(8).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - tbaa_label(self.module.clone(), intrinsics, "memory", load, Some(0)); + tbaa_label(&self.module, intrinsics, "memory", load, Some(0)); state.push1(result); } Operator::I32AtomicLoad8U { ref memarg } => { @@ -5947,7 +5933,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(1).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - tbaa_label(self.module.clone(), intrinsics, "memory", load, Some(0)); + tbaa_label(&self.module, intrinsics, "memory", load, Some(0)); let result = builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); state.push1_extra(result, ExtraInfo::arithmetic_f32()); @@ -5980,7 +5966,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(2).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - tbaa_label(self.module.clone(), intrinsics, "memory", load, Some(0)); + tbaa_label(&self.module, intrinsics, "memory", load, Some(0)); let result = builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); state.push1_extra(result, ExtraInfo::arithmetic_f32()); @@ -6013,7 +5999,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(1).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - tbaa_label(self.module.clone(), intrinsics, "memory", load, Some(0)); + tbaa_label(&self.module, intrinsics, "memory", load, Some(0)); let result = builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1_extra(result, ExtraInfo::arithmetic_f64()); @@ -6046,7 +6032,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(2).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - tbaa_label(self.module.clone(), intrinsics, "memory", load, Some(0)); + tbaa_label(&self.module, intrinsics, "memory", load, Some(0)); let result = builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1_extra(result, ExtraInfo::arithmetic_f64()); @@ -6079,7 +6065,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(4).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - tbaa_label(self.module.clone(), intrinsics, "memory", load, Some(0)); + tbaa_label(&self.module, intrinsics, "memory", load, Some(0)); let result = builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1_extra(result, ExtraInfo::arithmetic_f64()); @@ -6111,7 +6097,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { store .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); + tbaa_label(&self.module, intrinsics, "memory", store, Some(0)); } Operator::I64AtomicStore { ref memarg } => { let value = state.pop1()?; @@ -6140,7 +6126,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { store .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); + tbaa_label(&self.module, intrinsics, "memory", store, Some(0)); } Operator::I32AtomicStore8 { ref memarg } | Operator::I64AtomicStore8 { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6171,7 +6157,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { store .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); + tbaa_label(&self.module, intrinsics, "memory", store, Some(0)); } Operator::I32AtomicStore16 { ref memarg } | Operator::I64AtomicStore16 { ref memarg } => { @@ -6203,7 +6189,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { store .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); + tbaa_label(&self.module, intrinsics, "memory", store, Some(0)); } Operator::I64AtomicStore32 { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6234,7 +6220,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { store .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); + tbaa_label(&self.module, intrinsics, "memory", store, Some(0)); } Operator::I32AtomicRmw8UAdd { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -6269,7 +6255,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -6311,7 +6297,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -6351,7 +6337,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -6392,7 +6378,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -6434,7 +6420,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -6476,7 +6462,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -6516,7 +6502,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -6557,7 +6543,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -6599,7 +6585,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -6639,7 +6625,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -6680,7 +6666,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -6722,7 +6708,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -6764,7 +6750,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -6804,7 +6790,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -6845,7 +6831,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -6887,7 +6873,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -6927,7 +6913,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -6968,7 +6954,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7010,7 +6996,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7052,7 +7038,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7092,7 +7078,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7133,7 +7119,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7175,7 +7161,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7215,7 +7201,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7257,7 +7243,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7299,7 +7285,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7341,7 +7327,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7381,7 +7367,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7422,7 +7408,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7464,7 +7450,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7504,7 +7490,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7545,7 +7531,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7587,7 +7573,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7629,7 +7615,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7669,7 +7655,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7710,7 +7696,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7752,7 +7738,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7792,7 +7778,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7833,7 +7819,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7875,7 +7861,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7917,7 +7903,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -7957,7 +7943,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -8004,7 +7990,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -8056,7 +8042,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -8104,7 +8090,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -8152,7 +8138,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -8204,7 +8190,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -8256,7 +8242,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -8304,7 +8290,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .unwrap(); tbaa_label( - self.module.clone(), + &self.module, intrinsics, "memory", old.as_instruction_value().unwrap(), @@ -8430,10 +8416,35 @@ impl From for CodegenError { } } -impl ModuleCodeGenerator - for LLVMModuleCodeGenerator +impl Drop for LLVMModuleCodeGenerator<'_> { + fn drop(&mut self) { + // Ensure that all members of the context are dropped before we drop the context. + drop(self.builder.take()); + drop(self.intrinsics.take()); + self.functions.clear(); + self.signatures.clear(); + assert!( + Rc::strong_count(&*self.module) == 1, + "references to module live while dropping LLVMModuleCodeGenerator" + ); + unsafe { + ManuallyDrop::drop(&mut self.personality_func); + ManuallyDrop::drop(&mut self.module); + }; + let context = self.context.take(); + match context { + None => {} + Some(context_ref) => unsafe { + Box::from_raw(context_ref as *const Context as *mut Context); + }, + } + } +} + +impl<'ctx> ModuleCodeGenerator, LLVMBackend, CodegenError> + for LLVMModuleCodeGenerator<'ctx> { - fn new() -> LLVMModuleCodeGenerator { + fn new() -> LLVMModuleCodeGenerator<'ctx> { Self::new_with_target(None, None, None) } @@ -8441,8 +8452,9 @@ impl ModuleCodeGenerator triple: Option, cpu_name: Option, cpu_features: Option, - ) -> LLVMModuleCodeGenerator { - let context = Context::create(); + ) -> LLVMModuleCodeGenerator<'ctx> { + let context_ptr = Box::into_raw(Box::new(Context::create())); + let context = unsafe { &*context_ptr }; let module = context.create_module("module"); let triple = triple.unwrap_or(TargetMachine::get_default_triple().to_string()); @@ -8488,14 +8500,14 @@ impl ModuleCodeGenerator context: Some(context), builder: Some(builder), intrinsics: Some(intrinsics), - module: Rc::new(RefCell::new(module)), + module: ManuallyDrop::new(Rc::new(RefCell::new(module))), functions: vec![], signatures: Map::new(), signatures_raw: Map::new(), function_signatures: None, llvm_functions: Rc::new(RefCell::new(HashMap::new())), func_import_count: 0, - personality_func, + personality_func: ManuallyDrop::new(personality_func), stackmaps: Rc::new(RefCell::new(StackmapRegistry::default())), track_state: false, target_machine, @@ -8513,7 +8525,7 @@ impl ModuleCodeGenerator fn next_function( &mut self, _module_info: Arc>, - ) -> Result<&mut LLVMFunctionCodeGenerator, CodegenError> { + ) -> Result<&mut LLVMFunctionCodeGenerator<'ctx>, CodegenError> { // Creates a new function and returns the function-scope code generator for it. let (context, builder, intrinsics) = match self.functions.last_mut() { Some(x) => ( @@ -8533,14 +8545,14 @@ impl ModuleCodeGenerator let func_sig = self.signatures_raw[sig_id].clone(); let function = &self.llvm_functions.borrow_mut()[&func_index]; - function.set_personality_function(self.personality_func); + function.set_personality_function(*self.personality_func); - let mut state = State::new(); - let entry_block = context.append_basic_block(&function, "entry"); + let mut state: State<'ctx> = 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"); + let return_block = context.append_basic_block(*function, "return"); builder.position_at_end(&return_block); let phis: SmallVec<[PhiValue; 1]> = func_sig @@ -8602,7 +8614,7 @@ impl ModuleCodeGenerator index: local_func_index, opcode_offset: 0, track_state: self.track_state, - module: self.module.clone(), + module: (*self.module).clone(), }; self.functions.push(code); Ok(self.functions.last_mut().unwrap()) @@ -8688,7 +8700,7 @@ impl ModuleCodeGenerator let stackmaps = self.stackmaps.borrow(); let (backend, cache_gen) = LLVMBackend::new( - self.module.clone(), + (*self.module).clone(), self.intrinsics.take().unwrap(), &*stackmaps, module_info, diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index 2e3466e45ca..c983e41752a 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -12,7 +12,6 @@ use inkwell::{ }; use std::cell::RefCell; use std::collections::HashMap; -use std::marker::PhantomData; use std::rc::Rc; use wasmer_runtime_core::{ memory::MemoryType, @@ -25,7 +24,7 @@ use wasmer_runtime_core::{ vm::{Ctx, INTERNALS_SIZE}, }; -fn type_to_llvm_ptr(intrinsics: &Intrinsics, ty: Type) -> PointerType { +fn type_to_llvm_ptr<'ctx>(intrinsics: &Intrinsics<'ctx>, ty: Type) -> PointerType<'ctx> { match ty { Type::I32 => intrinsics.i32_ptr_ty, Type::I64 => intrinsics.i64_ptr_ty, @@ -35,124 +34,124 @@ fn type_to_llvm_ptr(intrinsics: &Intrinsics, ty: Type) -> PointerType { } } -pub struct Intrinsics { - pub ctlz_i32: FunctionValue, - pub ctlz_i64: FunctionValue, - - pub cttz_i32: FunctionValue, - pub cttz_i64: FunctionValue, - - pub ctpop_i32: FunctionValue, - pub ctpop_i64: FunctionValue, - - pub sqrt_f32: FunctionValue, - pub sqrt_f64: FunctionValue, - pub sqrt_f32x4: FunctionValue, - pub sqrt_f64x2: FunctionValue, - - pub ceil_f32: FunctionValue, - pub ceil_f64: FunctionValue, - - pub floor_f32: FunctionValue, - pub floor_f64: FunctionValue, - - pub trunc_f32: FunctionValue, - pub trunc_f64: FunctionValue, - - pub nearbyint_f32: FunctionValue, - pub nearbyint_f64: FunctionValue, - - pub fabs_f32: FunctionValue, - pub fabs_f64: FunctionValue, - pub fabs_f32x4: FunctionValue, - pub fabs_f64x2: FunctionValue, - - pub copysign_f32: FunctionValue, - pub copysign_f64: FunctionValue, - - pub sadd_sat_i8x16: FunctionValue, - pub sadd_sat_i16x8: FunctionValue, - pub uadd_sat_i8x16: FunctionValue, - pub uadd_sat_i16x8: FunctionValue, - - pub ssub_sat_i8x16: FunctionValue, - pub ssub_sat_i16x8: FunctionValue, - pub usub_sat_i8x16: FunctionValue, - pub usub_sat_i16x8: FunctionValue, - - pub expect_i1: FunctionValue, - pub trap: FunctionValue, - - pub void_ty: VoidType, - pub i1_ty: IntType, - pub i8_ty: IntType, - pub i16_ty: IntType, - pub i32_ty: IntType, - pub i64_ty: IntType, - pub i128_ty: IntType, - pub f32_ty: FloatType, - pub f64_ty: FloatType, - - pub i1x128_ty: VectorType, - pub i8x16_ty: VectorType, - pub i16x8_ty: VectorType, - pub i32x4_ty: VectorType, - pub i64x2_ty: VectorType, - pub f32x4_ty: VectorType, - pub f64x2_ty: VectorType, - - pub i8_ptr_ty: PointerType, - pub i16_ptr_ty: PointerType, - pub i32_ptr_ty: PointerType, - pub i64_ptr_ty: PointerType, - pub i128_ptr_ty: PointerType, - pub f32_ptr_ty: PointerType, - pub f64_ptr_ty: PointerType, - - pub anyfunc_ty: StructType, - - pub i1_zero: IntValue, - pub i8_zero: IntValue, - pub i32_zero: IntValue, - pub i64_zero: IntValue, - 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, - pub trap_call_indirect_oob: BasicValueEnum, - pub trap_memory_oob: BasicValueEnum, - pub trap_illegal_arithmetic: BasicValueEnum, - pub trap_misaligned_atomic: BasicValueEnum, +pub struct Intrinsics<'ctx> { + pub ctlz_i32: FunctionValue<'ctx>, + pub ctlz_i64: FunctionValue<'ctx>, + + pub cttz_i32: FunctionValue<'ctx>, + pub cttz_i64: FunctionValue<'ctx>, + + pub ctpop_i32: FunctionValue<'ctx>, + pub ctpop_i64: FunctionValue<'ctx>, + + pub sqrt_f32: FunctionValue<'ctx>, + pub sqrt_f64: FunctionValue<'ctx>, + pub sqrt_f32x4: FunctionValue<'ctx>, + pub sqrt_f64x2: FunctionValue<'ctx>, + + pub ceil_f32: FunctionValue<'ctx>, + pub ceil_f64: FunctionValue<'ctx>, + + pub floor_f32: FunctionValue<'ctx>, + pub floor_f64: FunctionValue<'ctx>, + + pub trunc_f32: FunctionValue<'ctx>, + pub trunc_f64: FunctionValue<'ctx>, + + pub nearbyint_f32: FunctionValue<'ctx>, + pub nearbyint_f64: FunctionValue<'ctx>, + + pub fabs_f32: FunctionValue<'ctx>, + pub fabs_f64: FunctionValue<'ctx>, + pub fabs_f32x4: FunctionValue<'ctx>, + pub fabs_f64x2: FunctionValue<'ctx>, + + pub copysign_f32: FunctionValue<'ctx>, + pub copysign_f64: FunctionValue<'ctx>, + + pub sadd_sat_i8x16: FunctionValue<'ctx>, + pub sadd_sat_i16x8: FunctionValue<'ctx>, + pub uadd_sat_i8x16: FunctionValue<'ctx>, + pub uadd_sat_i16x8: FunctionValue<'ctx>, + + pub ssub_sat_i8x16: FunctionValue<'ctx>, + pub ssub_sat_i16x8: FunctionValue<'ctx>, + pub usub_sat_i8x16: FunctionValue<'ctx>, + pub usub_sat_i16x8: FunctionValue<'ctx>, + + pub expect_i1: FunctionValue<'ctx>, + pub trap: FunctionValue<'ctx>, + + pub void_ty: VoidType<'ctx>, + pub i1_ty: IntType<'ctx>, + pub i8_ty: IntType<'ctx>, + pub i16_ty: IntType<'ctx>, + pub i32_ty: IntType<'ctx>, + pub i64_ty: IntType<'ctx>, + pub i128_ty: IntType<'ctx>, + pub f32_ty: FloatType<'ctx>, + pub f64_ty: FloatType<'ctx>, + + pub i1x128_ty: VectorType<'ctx>, + pub i8x16_ty: VectorType<'ctx>, + pub i16x8_ty: VectorType<'ctx>, + pub i32x4_ty: VectorType<'ctx>, + pub i64x2_ty: VectorType<'ctx>, + pub f32x4_ty: VectorType<'ctx>, + pub f64x2_ty: VectorType<'ctx>, + + pub i8_ptr_ty: PointerType<'ctx>, + pub i16_ptr_ty: PointerType<'ctx>, + pub i32_ptr_ty: PointerType<'ctx>, + pub i64_ptr_ty: PointerType<'ctx>, + pub i128_ptr_ty: PointerType<'ctx>, + pub f32_ptr_ty: PointerType<'ctx>, + pub f64_ptr_ty: PointerType<'ctx>, + + pub anyfunc_ty: StructType<'ctx>, + + pub i1_zero: IntValue<'ctx>, + pub i8_zero: IntValue<'ctx>, + pub i32_zero: IntValue<'ctx>, + pub i64_zero: IntValue<'ctx>, + pub i128_zero: IntValue<'ctx>, + pub f32_zero: FloatValue<'ctx>, + pub f64_zero: FloatValue<'ctx>, + pub f32x4_zero: VectorValue<'ctx>, + pub f64x2_zero: VectorValue<'ctx>, + + pub trap_unreachable: BasicValueEnum<'ctx>, + pub trap_call_indirect_sig: BasicValueEnum<'ctx>, + pub trap_call_indirect_oob: BasicValueEnum<'ctx>, + pub trap_memory_oob: BasicValueEnum<'ctx>, + pub trap_illegal_arithmetic: BasicValueEnum<'ctx>, + pub trap_misaligned_atomic: BasicValueEnum<'ctx>, // VM intrinsics. - pub memory_grow_dynamic_local: FunctionValue, - pub memory_grow_static_local: FunctionValue, - pub memory_grow_shared_local: FunctionValue, - pub memory_grow_dynamic_import: FunctionValue, - pub memory_grow_static_import: FunctionValue, - pub memory_grow_shared_import: FunctionValue, - - pub memory_size_dynamic_local: FunctionValue, - pub memory_size_static_local: FunctionValue, - pub memory_size_shared_local: FunctionValue, - pub memory_size_dynamic_import: FunctionValue, - pub memory_size_static_import: FunctionValue, - pub memory_size_shared_import: FunctionValue, - - pub throw_trap: FunctionValue, - pub throw_breakpoint: FunctionValue, - - pub experimental_stackmap: FunctionValue, - - pub ctx_ptr_ty: PointerType, + pub memory_grow_dynamic_local: FunctionValue<'ctx>, + pub memory_grow_static_local: FunctionValue<'ctx>, + pub memory_grow_shared_local: FunctionValue<'ctx>, + pub memory_grow_dynamic_import: FunctionValue<'ctx>, + pub memory_grow_static_import: FunctionValue<'ctx>, + pub memory_grow_shared_import: FunctionValue<'ctx>, + + pub memory_size_dynamic_local: FunctionValue<'ctx>, + pub memory_size_static_local: FunctionValue<'ctx>, + pub memory_size_shared_local: FunctionValue<'ctx>, + pub memory_size_dynamic_import: FunctionValue<'ctx>, + pub memory_size_static_import: FunctionValue<'ctx>, + pub memory_size_shared_import: FunctionValue<'ctx>, + + pub throw_trap: FunctionValue<'ctx>, + pub throw_breakpoint: FunctionValue<'ctx>, + + pub experimental_stackmap: FunctionValue<'ctx>, + + pub ctx_ptr_ty: PointerType<'ctx>, } -impl Intrinsics { - pub fn declare(module: &Module, context: &Context) -> Self { +impl<'ctx> Intrinsics<'ctx> { + pub fn declare(module: &Module<'ctx>, context: &'ctx Context) -> Self { let void_ty = context.void_type(); let i1_ty = context.bool_type(); let i8_ty = context.i8_type(); @@ -560,66 +559,64 @@ impl Intrinsics { } #[derive(Clone, Copy)] -pub enum MemoryCache { +pub enum MemoryCache<'ctx> { /// The memory moves around. Dynamic { - ptr_to_base_ptr: PointerValue, - ptr_to_bounds: PointerValue, + ptr_to_base_ptr: PointerValue<'ctx>, + ptr_to_bounds: PointerValue<'ctx>, minimum: Pages, maximum: Option, }, /// The memory is always in the same place. Static { - base_ptr: PointerValue, - bounds: IntValue, + base_ptr: PointerValue<'ctx>, + bounds: IntValue<'ctx>, minimum: Pages, maximum: Option, }, } -struct TableCache { - ptr_to_base_ptr: PointerValue, - ptr_to_bounds: PointerValue, +struct TableCache<'ctx> { + ptr_to_base_ptr: PointerValue<'ctx>, + ptr_to_bounds: PointerValue<'ctx>, } #[derive(Clone, Copy)] -pub enum GlobalCache { - Mut { ptr_to_value: PointerValue }, - Const { value: BasicValueEnum }, +pub enum GlobalCache<'ctx> { + Mut { ptr_to_value: PointerValue<'ctx> }, + Const { value: BasicValueEnum<'ctx> }, } -struct ImportedFuncCache { - func_ptr: PointerValue, - ctx_ptr: PointerValue, +struct ImportedFuncCache<'ctx> { + func_ptr: PointerValue<'ctx>, + ctx_ptr: PointerValue<'ctx>, } -pub struct CtxType<'a> { - ctx_ptr_value: PointerValue, +pub struct CtxType<'a, 'ctx> { + ctx_ptr_value: PointerValue<'ctx>, info: &'a ModuleInfo, - cache_builder: Builder, + cache_builder: Builder<'ctx>, - cached_signal_mem: Option, + cached_signal_mem: Option>, - cached_memories: HashMap, - cached_tables: HashMap, - cached_sigindices: HashMap, - cached_globals: HashMap, - cached_imported_functions: HashMap, - - _phantom: PhantomData<&'a FunctionValue>, + cached_memories: HashMap>, + cached_tables: HashMap>, + cached_sigindices: HashMap>, + cached_globals: HashMap>, + cached_imported_functions: HashMap>, } fn offset_to_index(offset: u8) -> u32 { (offset as usize / ::std::mem::size_of::()) as u32 } -impl<'a> CtxType<'a> { +impl<'a, 'ctx> CtxType<'a, 'ctx> { pub fn new( info: &'a ModuleInfo, - func_value: &'a FunctionValue, - cache_builder: Builder, - ) -> CtxType<'a> { + func_value: &FunctionValue<'ctx>, + cache_builder: Builder<'ctx>, + ) -> CtxType<'a, 'ctx> { CtxType { ctx_ptr_value: func_value.get_nth_param(0).unwrap().into_pointer_value(), @@ -633,16 +630,14 @@ impl<'a> CtxType<'a> { cached_sigindices: HashMap::new(), cached_globals: HashMap::new(), cached_imported_functions: HashMap::new(), - - _phantom: PhantomData, } } - pub fn basic(&self) -> BasicValueEnum { + pub fn basic(&self) -> BasicValueEnum<'ctx> { self.ctx_ptr_value.as_basic_value_enum() } - pub fn signal_mem(&mut self) -> PointerValue { + pub fn signal_mem(&mut self) -> PointerValue<'ctx> { if let Some(x) = self.cached_signal_mem { return x; } @@ -666,9 +661,9 @@ impl<'a> CtxType<'a> { pub fn memory( &mut self, index: MemoryIndex, - intrinsics: &Intrinsics, - module: Rc>, - ) -> MemoryCache { + intrinsics: &Intrinsics<'ctx>, + module: Rc>>, + ) -> MemoryCache<'ctx> { let (cached_memories, info, ctx_ptr_value, cache_builder) = ( &mut self.cached_memories, self.info, @@ -713,7 +708,7 @@ impl<'a> CtxType<'a> { .build_load(memory_array_ptr_ptr, "memory_array_ptr") .into_pointer_value(); tbaa_label( - module.clone(), + &module, intrinsics, field_name, memory_array_ptr.as_instruction_value().unwrap(), @@ -731,7 +726,7 @@ impl<'a> CtxType<'a> { .build_load(memory_ptr_ptr, "memory_ptr") .into_pointer_value(); tbaa_label( - module.clone(), + &module, intrinsics, "memory_ptr", memory_ptr.as_instruction_value().unwrap(), @@ -760,14 +755,14 @@ impl<'a> CtxType<'a> { .build_load(ptr_to_bounds, "bounds") .into_int_value(); tbaa_label( - module.clone(), + &module, intrinsics, "static_memory_base", base_ptr.as_instruction_value().unwrap(), Some(index as u32), ); tbaa_label( - module.clone(), + &module, intrinsics, "static_memory_bounds", bounds.as_instruction_value().unwrap(), @@ -787,9 +782,9 @@ impl<'a> CtxType<'a> { pub fn table_prepare( &mut self, index: TableIndex, - intrinsics: &Intrinsics, - module: Rc>, - ) -> (PointerValue, PointerValue) { + intrinsics: &Intrinsics<'ctx>, + module: Rc>>, + ) -> (PointerValue<'ctx>, PointerValue<'ctx>) { let (cached_tables, info, ctx_ptr_value, cache_builder) = ( &mut self.cached_tables, self.info, @@ -830,7 +825,7 @@ impl<'a> CtxType<'a> { .build_load(table_array_ptr_ptr, "table_array_ptr") .into_pointer_value(); tbaa_label( - module.clone(), + &module, intrinsics, field_name, table_array_ptr.as_instruction_value().unwrap(), @@ -844,7 +839,7 @@ impl<'a> CtxType<'a> { .build_load(table_ptr_ptr, "table_ptr") .into_pointer_value(); tbaa_label( - module.clone(), + &module, intrinsics, "table_ptr", table_array_ptr.as_instruction_value().unwrap(), @@ -870,10 +865,10 @@ impl<'a> CtxType<'a> { pub fn table( &mut self, index: TableIndex, - intrinsics: &Intrinsics, - module: Rc>, - builder: &Builder, - ) -> (PointerValue, IntValue) { + intrinsics: &Intrinsics<'ctx>, + module: Rc>>, + builder: &Builder<'ctx>, + ) -> (PointerValue<'ctx>, IntValue<'ctx>) { let (ptr_to_base_ptr, ptr_to_bounds) = self.table_prepare(index, intrinsics, module.clone()); let base_ptr = builder @@ -881,14 +876,14 @@ impl<'a> CtxType<'a> { .into_pointer_value(); let bounds = builder.build_load(ptr_to_bounds, "bounds").into_int_value(); tbaa_label( - module.clone(), + &module, intrinsics, "table_base_ptr", base_ptr.as_instruction_value().unwrap(), Some(index.index() as u32), ); tbaa_label( - module.clone(), + &module, intrinsics, "table_bounds", bounds.as_instruction_value().unwrap(), @@ -897,7 +892,11 @@ impl<'a> CtxType<'a> { (base_ptr, bounds) } - pub fn dynamic_sigindex(&mut self, index: SigIndex, intrinsics: &Intrinsics) -> IntValue { + pub fn dynamic_sigindex( + &mut self, + index: SigIndex, + intrinsics: &Intrinsics<'ctx>, + ) -> IntValue<'ctx> { let (cached_sigindices, ctx_ptr_value, cache_builder) = ( &mut self.cached_sigindices, self.ctx_ptr_value, @@ -934,9 +933,9 @@ impl<'a> CtxType<'a> { pub fn global_cache( &mut self, index: GlobalIndex, - intrinsics: &Intrinsics, - module: Rc>, - ) -> GlobalCache { + intrinsics: &Intrinsics<'ctx>, + module: Rc>>, + ) -> GlobalCache<'ctx> { let (cached_globals, ctx_ptr_value, info, cache_builder) = ( &mut self.cached_globals, self.ctx_ptr_value, @@ -987,7 +986,7 @@ impl<'a> CtxType<'a> { .build_load(globals_array_ptr_ptr, "global_array_ptr") .into_pointer_value(); tbaa_label( - module.clone(), + &module, intrinsics, field_name, global_array_ptr.as_instruction_value().unwrap(), @@ -1005,7 +1004,7 @@ impl<'a> CtxType<'a> { .build_load(global_ptr_ptr, "global_ptr") .into_pointer_value(); tbaa_label( - module.clone(), + &module, intrinsics, "global_ptr", global_ptr.as_instruction_value().unwrap(), @@ -1022,7 +1021,7 @@ impl<'a> CtxType<'a> { } else { let value = cache_builder.build_load(global_ptr_typed, "global_value"); tbaa_label( - module.clone(), + &module, intrinsics, "global", value.as_instruction_value().unwrap(), @@ -1036,9 +1035,9 @@ impl<'a> CtxType<'a> { pub fn imported_func( &mut self, index: ImportedFuncIndex, - intrinsics: &Intrinsics, - module: Rc>, - ) -> (PointerValue, PointerValue) { + intrinsics: &Intrinsics<'ctx>, + module: Rc>>, + ) -> (PointerValue<'ctx>, PointerValue<'ctx>) { let (cached_imported_functions, ctx_ptr_value, cache_builder) = ( &mut self.cached_imported_functions, self.ctx_ptr_value, @@ -1057,7 +1056,7 @@ impl<'a> CtxType<'a> { .build_load(func_array_ptr_ptr, "func_array_ptr") .into_pointer_value(); tbaa_label( - module.clone(), + &module, intrinsics, "context_field_ptr_to_imported_funcs", func_array_ptr.as_instruction_value().unwrap(), @@ -1089,14 +1088,14 @@ impl<'a> CtxType<'a> { .build_load(ctx_ptr_ptr, "ctx_ptr") .into_pointer_value(); tbaa_label( - module.clone(), + &module, intrinsics, "imported_func_ptr", func_ptr.as_instruction_value().unwrap(), Some(index.index() as u32), ); tbaa_label( - module.clone(), + &module, intrinsics, "imported_func_ctx_ptr", ctx_ptr.as_instruction_value().unwrap(), @@ -1112,10 +1111,10 @@ impl<'a> CtxType<'a> { pub fn internal_field( &mut self, index: usize, - intrinsics: &Intrinsics, - module: Rc>, - builder: &Builder, - ) -> PointerValue { + intrinsics: &Intrinsics<'ctx>, + module: Rc>>, + builder: &Builder<'ctx>, + ) -> PointerValue<'ctx> { assert!(index < INTERNALS_SIZE); let local_internals_ptr_ptr = unsafe { @@ -1129,7 +1128,7 @@ impl<'a> CtxType<'a> { .build_load(local_internals_ptr_ptr, "local_internals_ptr") .into_pointer_value(); tbaa_label( - module.clone(), + &module, intrinsics, "context_field_ptr_to_internals", local_internals_ptr.as_instruction_value().unwrap(), @@ -1147,11 +1146,11 @@ 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, +pub fn tbaa_label<'ctx>( + module: &Rc>>, + intrinsics: &Intrinsics<'ctx>, label: &str, - instruction: InstructionValue, + instruction: InstructionValue<'ctx>, index: Option, ) { // To convey to LLVM that two pointers must be pointing to distinct memory, @@ -1170,6 +1169,12 @@ pub fn tbaa_label( let module = module.borrow_mut(); let context = module.get_context(); + // TODO: ContextRef can't return us the lifetime from module through Deref. + // This could be fixed once generic_associated_types is stable. + let context2 = &*context; + let context = unsafe { std::mem::transmute::<&Context, &'ctx Context>(context2) }; + std::mem::forget(context2); + // `!wasmer_tbaa_root = {}`, the TBAA root node for wasmer. let tbaa_root = module .get_global_metadata("wasmer_tbaa_root") diff --git a/lib/llvm-backend/src/lib.rs b/lib/llvm-backend/src/lib.rs index 8194f797a45..2b3f7d2e67c 100644 --- a/lib/llvm-backend/src/lib.rs +++ b/lib/llvm-backend/src/lib.rs @@ -29,8 +29,8 @@ pub use code::LLVMModuleCodeGenerator as ModuleCodeGenerator; use wasmer_runtime_core::codegen::SimpleStreamingCompilerGen; pub type LLVMCompiler = SimpleStreamingCompilerGen< - code::LLVMModuleCodeGenerator, - code::LLVMFunctionCodeGenerator, + code::LLVMModuleCodeGenerator<'static>, + code::LLVMFunctionCodeGenerator<'static>, backend::LLVMBackend, code::CodegenError, >; diff --git a/lib/llvm-backend/src/state.rs b/lib/llvm-backend/src/state.rs index 82ef5ec8813..e870b6627fe 100644 --- a/lib/llvm-backend/src/state.rs +++ b/lib/llvm-backend/src/state.rs @@ -8,23 +8,23 @@ use std::ops::{BitAnd, BitOr, BitOrAssign}; use wasmparser::BinaryReaderError; #[derive(Debug)] -pub enum ControlFrame { +pub enum ControlFrame<'ctx> { Block { next: BasicBlock, - phis: SmallVec<[PhiValue; 1]>, + phis: SmallVec<[PhiValue<'ctx>; 1]>, stack_size_snapshot: usize, }, Loop { body: BasicBlock, next: BasicBlock, - phis: SmallVec<[PhiValue; 1]>, + phis: SmallVec<[PhiValue<'ctx>; 1]>, stack_size_snapshot: usize, }, IfElse { if_then: BasicBlock, if_else: BasicBlock, next: BasicBlock, - phis: SmallVec<[PhiValue; 1]>, + phis: SmallVec<[PhiValue<'ctx>; 1]>, stack_size_snapshot: usize, if_else_state: IfElseState, }, @@ -36,7 +36,7 @@ pub enum IfElseState { Else, } -impl ControlFrame { +impl<'ctx> ControlFrame<'ctx> { pub fn code_after(&self) -> &BasicBlock { match self { ControlFrame::Block { ref next, .. } @@ -52,7 +52,7 @@ impl ControlFrame { } } - pub fn phis(&self) -> &[PhiValue] { + pub fn phis(&self) -> &[PhiValue<'ctx>] { match self { ControlFrame::Block { ref phis, .. } | ControlFrame::Loop { ref phis, .. } @@ -193,15 +193,15 @@ impl BitAnd for ExtraInfo { } #[derive(Debug)] -pub struct State { - pub stack: Vec<(BasicValueEnum, ExtraInfo)>, - control_stack: Vec, +pub struct State<'ctx> { + pub stack: Vec<(BasicValueEnum<'ctx>, ExtraInfo)>, + control_stack: Vec>, value_counter: Cell, pub reachable: bool, } -impl State { +impl<'ctx> State<'ctx> { pub fn new() -> Self { Self { stack: vec![], @@ -211,7 +211,7 @@ impl State { } } - pub fn reset_stack(&mut self, frame: &ControlFrame) { + pub fn reset_stack(&mut self, frame: &ControlFrame<'ctx>) { let stack_size_snapshot = match frame { ControlFrame::Block { stack_size_snapshot, @@ -229,14 +229,14 @@ impl State { self.stack.truncate(stack_size_snapshot); } - pub fn outermost_frame(&self) -> Result<&ControlFrame, BinaryReaderError> { + pub fn outermost_frame(&self) -> Result<&ControlFrame<'ctx>, BinaryReaderError> { self.control_stack.get(0).ok_or(BinaryReaderError { message: "invalid control stack depth", offset: -1isize as usize, }) } - pub fn frame_at_depth(&self, depth: u32) -> Result<&ControlFrame, BinaryReaderError> { + pub fn frame_at_depth(&self, depth: u32) -> Result<&ControlFrame<'ctx>, BinaryReaderError> { let index = self.control_stack.len() - 1 - (depth as usize); self.control_stack.get(index).ok_or(BinaryReaderError { message: "invalid control stack depth", @@ -247,7 +247,7 @@ impl State { pub fn frame_at_depth_mut( &mut self, depth: u32, - ) -> Result<&mut ControlFrame, BinaryReaderError> { + ) -> Result<&mut ControlFrame<'ctx>, BinaryReaderError> { let index = self.control_stack.len() - 1 - (depth as usize); self.control_stack.get_mut(index).ok_or(BinaryReaderError { message: "invalid control stack depth", @@ -255,7 +255,7 @@ impl State { }) } - pub fn pop_frame(&mut self) -> Result { + pub fn pop_frame(&mut self) -> Result, BinaryReaderError> { self.control_stack.pop().ok_or(BinaryReaderError { message: "cannot pop from control stack", offset: -1isize as usize, @@ -269,26 +269,28 @@ impl State { s } - pub fn push1(&mut self, value: T) { + pub fn push1>(&mut self, value: T) { self.push1_extra(value, Default::default()); } - pub fn push1_extra(&mut self, value: T, info: ExtraInfo) { + 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 { + pub fn pop1(&mut self) -> Result, BinaryReaderError> { Ok(self.pop1_extra()?.0) } - pub fn pop1_extra(&mut self) -> Result<(BasicValueEnum, ExtraInfo), BinaryReaderError> { + pub fn pop1_extra(&mut self) -> Result<(BasicValueEnum<'ctx>, ExtraInfo), BinaryReaderError> { self.stack.pop().ok_or(BinaryReaderError { message: "invalid value stack", offset: -1isize as usize, }) } - pub fn pop2(&mut self) -> Result<(BasicValueEnum, BasicValueEnum), BinaryReaderError> { + pub fn pop2( + &mut self, + ) -> Result<(BasicValueEnum<'ctx>, BasicValueEnum<'ctx>), BinaryReaderError> { let v2 = self.pop1()?; let v1 = self.pop1()?; Ok((v1, v2)) @@ -296,7 +298,13 @@ impl State { pub fn pop2_extra( &mut self, - ) -> Result<((BasicValueEnum, ExtraInfo), (BasicValueEnum, ExtraInfo)), BinaryReaderError> { + ) -> Result< + ( + (BasicValueEnum<'ctx>, ExtraInfo), + (BasicValueEnum<'ctx>, ExtraInfo), + ), + BinaryReaderError, + > { let v2 = self.pop1_extra()?; let v1 = self.pop1_extra()?; Ok((v1, v2)) @@ -306,9 +314,9 @@ impl State { &mut self, ) -> Result< ( - (BasicValueEnum, ExtraInfo), - (BasicValueEnum, ExtraInfo), - (BasicValueEnum, ExtraInfo), + (BasicValueEnum<'ctx>, ExtraInfo), + (BasicValueEnum<'ctx>, ExtraInfo), + (BasicValueEnum<'ctx>, ExtraInfo), ), BinaryReaderError, > { @@ -318,7 +326,7 @@ impl State { Ok((v1, v2, v3)) } - pub fn peek1_extra(&self) -> Result<(BasicValueEnum, ExtraInfo), BinaryReaderError> { + pub fn peek1_extra(&self) -> Result<(BasicValueEnum<'ctx>, ExtraInfo), BinaryReaderError> { self.stack .get(self.stack.len() - 1) .ok_or(BinaryReaderError { @@ -328,14 +336,14 @@ impl State { .map(|v| *v) } - pub fn peekn(&self, n: usize) -> Result, 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> { + ) -> Result<&[(BasicValueEnum<'ctx>, ExtraInfo)], BinaryReaderError> { let new_len = self.stack.len().checked_sub(n).ok_or(BinaryReaderError { message: "invalid value stack", offset: -1isize as usize, @@ -347,7 +355,7 @@ impl State { pub fn popn_save_extra( &mut self, n: usize, - ) -> Result, BinaryReaderError> { + ) -> Result, ExtraInfo)>, BinaryReaderError> { let v = self.peekn_extra(n)?.to_vec(); self.popn(n)?; Ok(v) @@ -366,7 +374,7 @@ impl State { Ok(()) } - pub fn push_block(&mut self, next: BasicBlock, phis: SmallVec<[PhiValue; 1]>) { + pub fn push_block(&mut self, next: BasicBlock, phis: SmallVec<[PhiValue<'ctx>; 1]>) { self.control_stack.push(ControlFrame::Block { next, phis, @@ -374,7 +382,12 @@ impl State { }); } - pub fn push_loop(&mut self, body: BasicBlock, next: BasicBlock, phis: SmallVec<[PhiValue; 1]>) { + pub fn push_loop( + &mut self, + body: BasicBlock, + next: BasicBlock, + phis: SmallVec<[PhiValue<'ctx>; 1]>, + ) { self.control_stack.push(ControlFrame::Loop { body, next, @@ -388,7 +401,7 @@ impl State { if_then: BasicBlock, if_else: BasicBlock, next: BasicBlock, - phis: SmallVec<[PhiValue; 1]>, + phis: SmallVec<[PhiValue<'ctx>; 1]>, ) { self.control_stack.push(ControlFrame::IfElse { if_then, diff --git a/lib/llvm-backend/src/trampolines.rs b/lib/llvm-backend/src/trampolines.rs index c9bd50e1b47..c4894ef84ef 100644 --- a/lib/llvm-backend/src/trampolines.rs +++ b/lib/llvm-backend/src/trampolines.rs @@ -13,13 +13,13 @@ use wasmer_runtime_core::{ types::{FuncSig, SigIndex, Type}, }; -pub fn generate_trampolines( +pub fn generate_trampolines<'ctx>( info: &ModuleInfo, - signatures: &SliceMap, - module: &Module, - context: &Context, - builder: &Builder, - intrinsics: &Intrinsics, + signatures: &SliceMap>, + module: &Module<'ctx>, + context: &'ctx Context, + builder: &Builder<'ctx>, + intrinsics: &Intrinsics<'ctx>, ) -> Result<(), String> { for (sig_index, sig) in info.signatures.iter() { let func_type = signatures[sig_index]; @@ -47,14 +47,14 @@ pub fn generate_trampolines( Ok(()) } -fn generate_trampoline( +fn generate_trampoline<'ctx>( trampoline_func: FunctionValue, func_sig: &FuncSig, - context: &Context, - builder: &Builder, - intrinsics: &Intrinsics, + context: &'ctx Context, + builder: &Builder<'ctx>, + intrinsics: &Intrinsics<'ctx>, ) -> Result<(), String> { - let entry_block = context.append_basic_block(&trampoline_func, "entry"); + let entry_block = context.append_basic_block(trampoline_func, "entry"); builder.position_at_end(&entry_block); let (vmctx_ptr, func_ptr, args_ptr, returns_ptr) = match trampoline_func.get_params().as_slice() From fd0df9946b8fb7088cad4dbf54e031d42f80ffcf Mon Sep 17 00:00:00 2001 From: Asami Doi Date: Fri, 22 Nov 2019 19:02:57 +0900 Subject: [PATCH 276/342] Add "auto" backend to change the backend depending on the wasm file size --- CHANGELOG.md | 1 + lib/runtime-core/src/backend.rs | 4 ++++ lib/runtime-core/src/codegen.rs | 1 + lib/runtime/src/lib.rs | 5 ----- src/bin/wasmer.rs | 33 ++++++++++++++++++++++++++++----- 5 files changed, 34 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60ff5c652ec..c1de67bf893 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. +- [#1004](https://github.com/wasmerio/wasmer/pull/1004) Add the Auto backend to enable to adapt backend usage depending on wasm file executed. ## 0.11.0 - 2019-11-22 diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs index df4ef775160..febfdda0e98 100644 --- a/lib/runtime-core/src/backend.rs +++ b/lib/runtime-core/src/backend.rs @@ -28,6 +28,7 @@ pub enum Backend { Cranelift, Singlepass, LLVM, + Auto, } impl Backend { @@ -40,6 +41,7 @@ impl Backend { "singlepass", #[cfg(feature = "backend-llvm")] "llvm", + "auto", ] } @@ -50,6 +52,7 @@ impl Backend { Backend::Cranelift => "cranelift", Backend::Singlepass => "singlepass", Backend::LLVM => "llvm", + Backend::Auto => "auto", } } } @@ -67,6 +70,7 @@ impl std::str::FromStr for Backend { "singlepass" => Ok(Backend::Singlepass), "cranelift" => Ok(Backend::Cranelift), "llvm" => Ok(Backend::LLVM), + "auto" => Ok(Backend::Auto), _ => Err(format!("The backend {} doesn't exist", s)), } } diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index 7b4533296b9..991e05ed8ad 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -265,6 +265,7 @@ fn requires_pre_validation(backend: Backend) -> bool { Backend::Cranelift => true, Backend::LLVM => true, Backend::Singlepass => false, + Backend::Auto => false, } } diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index 2ac6c174261..0c832bf3020 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -254,11 +254,6 @@ pub fn compiler_for_backend(backend: Backend) -> Option> { #[cfg(feature = "llvm")] Backend::LLVM => Some(Box::new(wasmer_llvm_backend::LLVMCompiler::new())), - #[cfg(any( - not(feature = "llvm"), - not(feature = "singlepass"), - not(feature = "cranelift") - ))] _ => None, } } diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index a08f7bd532b..457b6f51060 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -10,7 +10,7 @@ extern crate structopt; use std::env; -use std::fs::{read_to_string, File}; +use std::fs::{metadata, read_to_string, File}; use std::io; use std::io::Read; use std::path::PathBuf; @@ -130,7 +130,7 @@ struct Run { #[cfg(target_arch = "x86_64")] #[structopt( long = "backend", - default_value = "cranelift", + default_value = "auto", case_insensitive = true, possible_values = Backend::variants(), )] @@ -855,8 +855,30 @@ fn interactive_shell(mut ctx: InteractiveShellContext) -> ShellExitOperation { } } -fn run(options: Run) { - match execute_wasm(&options) { +fn update_backend(options: &mut Run) { + let binary_size = match metadata(&options.path) { + Ok(wasm_binary) => wasm_binary.len(), + Err(_e) => 0, + }; + + // Update backend when a backend flag is `auto`. + // Use the Singlepass backend if it's enabled and the file provided is larger + // than 10MiB (10485760 bytes), or it's enabled and the target architecture + // is AArch64. Otherwise, use the Cranelift backend. + if options.backend == Backend::Auto { + if Backend::variants().contains(&Backend::Singlepass.to_string()) + && (binary_size > 10485760 || cfg!(target_arch = "aarch64")) + { + options.backend = Backend::Singlepass; + } else { + options.backend = Backend::Cranelift; + } + } +} + +fn run(options: &mut Run) { + update_backend(options); + match execute_wasm(options) { Ok(()) => {} Err(message) => { eprintln!("Error: {}", message); @@ -940,6 +962,7 @@ fn get_compiler_by_backend(backend: Backend, _opts: &Run) -> Option Box::new(LLVMCompiler::new()), #[cfg(not(feature = "backend-llvm"))] Backend::LLVM => return None, + Backend::Auto => return None, }) } @@ -958,7 +981,7 @@ fn main() { } }); match options { - CLIOptions::Run(options) => run(options), + CLIOptions::Run(mut options) => run(&mut options), #[cfg(not(target_os = "windows"))] CLIOptions::SelfUpdate => update::self_update(), #[cfg(target_os = "windows")] From cfa063502682c9b10dc07c1e3bb2fb56f48faa44 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 28 Nov 2019 02:49:52 +0800 Subject: [PATCH 277/342] 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 278/342] 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 279/342] 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 280/342] 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 281/342] 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 282/342] 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 7f3680c27a3f7e4c41e85ee5e4d289bfd921ea87 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 2 Dec 2019 15:36:45 +0100 Subject: [PATCH 283/342] fix(wasi) `get_wasi_version` is broken with multiple namespaces. If a module has multiple import namespaces, `get_wasi_version` is broken because it assumes a module must only have a single namespace. This patch fixes it by a slower `get_wasi_version` function, but a correct one. As soon as the `wasi_unstable` or `wasi_snapshot_preview1` namespace is met, `get_wasi_version` maps it to the respective `WasiVersion` variant. It assumes however that a module must hold a unique WASI version. --- lib/wasi/src/utils.rs | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/lib/wasi/src/utils.rs b/lib/wasi/src/utils.rs index b19a404884b..e7c24aff48f 100644 --- a/lib/wasi/src/utils.rs +++ b/lib/wasi/src/utils.rs @@ -18,24 +18,19 @@ pub enum WasiVersion { /// Detect the version of WASI being used from the namespace pub fn get_wasi_version(module: &Module) -> Option { - let mut import_iter = module + let namespace_table = &module.info().namespace_table; + + module .info() .imported_functions .iter() - .map(|(_, import_name)| import_name.namespace_index); + .find_map(|(_, import_name)| { + let namespace_index = import_name.namespace_index; - // returns None if empty - let first = import_iter.next()?; - if import_iter.all(|idx| idx == first) { - // once we know that all the namespaces are the same, we can use it to - // detect which version of WASI this is - match module.info().namespace_table.get(first) { - "wasi_unstable" => Some(WasiVersion::Snapshot0), - "wasi_snapshot_preview1" => Some(WasiVersion::Snapshot1), - _ => None, - } - } else { - // not all funcs have the same namespace, therefore it's not WASI - None - } + match namespace_table.get(namespace_index) { + "wasi_unstable" => Some(WasiVersion::Snapshot0), + "wasi_snapshot_preview1" => Some(WasiVersion::Snapshot1), + _ => None, + } + }) } From 8df0591ee57ef8bacbacbcb13a6c41129129ede3 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 2 Dec 2019 15:41:46 +0100 Subject: [PATCH 284/342] doc(changelog) Add #1028. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1de67bf893..79f9da5aa5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## **[Unreleased]** +- [#1028](https://github.com/wasmerio/wasmer/pull/1028) Fix `get_wasi_version` when a module has multiple import namespaces. - [#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. - [#1004](https://github.com/wasmerio/wasmer/pull/1004) Add the Auto backend to enable to adapt backend usage depending on wasm file executed. From a79beede727a28ccdd26456e4e0cd17d7cd9c03f Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 2 Dec 2019 15:46:08 +0100 Subject: [PATCH 285/342] =?UTF-8?q?feat(wasi)=20Add=20the=20=E2=80=9Cvolat?= =?UTF-8?q?ile=E2=80=9D=20`WasiVersion::Latest`=20version.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In addition to `Snapshot0` and `Snapshot1`, I believe it is an interesting API to provide the `Latest` version, so that the user can write: ```rust generate_import_object_for_version(WasiVersion::Latest, …); ``` This is a way to ensure that modules will run only if they come with the latest WASI version (in case of security issues for instance), by just updating the runtime. Note that it can be dangerous if not used carefully, but we assume the user knows what it does by sticking on a specific “floating” version. Also note that the `Latest` version is never returned by any API. It is provided only by the user. --- lib/wasi/src/lib.rs | 4 +++- lib/wasi/src/utils.rs | 9 ++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index ca439bfdbfe..712bfa4c737 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -142,7 +142,9 @@ pub fn generate_import_object_for_version( WasiVersion::Snapshot0 => { generate_import_object_snapshot0(args, envs, preopened_files, mapped_dirs) } - WasiVersion::Snapshot1 => generate_import_object(args, envs, preopened_files, mapped_dirs), + WasiVersion::Snapshot1 | WasiVersion::Latest => { + generate_import_object(args, envs, preopened_files, mapped_dirs) + } } } diff --git a/lib/wasi/src/utils.rs b/lib/wasi/src/utils.rs index b19a404884b..9774abe20e8 100644 --- a/lib/wasi/src/utils.rs +++ b/lib/wasi/src/utils.rs @@ -7,13 +7,16 @@ pub fn is_wasi_module(module: &Module) -> bool { get_wasi_version(module).is_some() } -/// The version of WASI. This is determined by the namespace string +/// The version of WASI. This is determined by the imports namespace +/// string. #[derive(Debug, Clone, Copy, PartialEq)] pub enum WasiVersion { - /// "wasi_unstable" + /// `wasi_unstable`. Snapshot0, - /// "wasi_snapshot_preview1" + /// `wasi_snapshot_preview1`. Snapshot1, + /// Latest version (for the moment, an alias to `Snapshot1`). + Latest, } /// Detect the version of WASI being used from the namespace From c916f0edaaf3520902a2c34c37c6b8ce454cf810 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 2 Dec 2019 15:55:38 +0100 Subject: [PATCH 286/342] doc(changelog) Add #1029. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1de67bf893..8340f947d4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## **[Unreleased]** +- [#1029](https://github.com/wasmerio/wasmer/pull/1029) Add the “floating” `WasiVersion::Latest` version. - [#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. - [#1004](https://github.com/wasmerio/wasmer/pull/1004) Add the Auto backend to enable to adapt backend usage depending on wasm file executed. From 04d8df0a46af0c6be6af9c1090eb7e7cda2ff97d Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 3 Dec 2019 01:46:06 +0800 Subject: [PATCH 287/342] 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 288/342] 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 289/342] 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 290/342] 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 291/342] 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 ab111443be09ed7824833c14958e2efcb8c005f1 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 2 Dec 2019 15:34:40 -0800 Subject: [PATCH 292/342] Improve default compiler story for wasmer cli This commit reenables the clif compiler as the default for wasmer cli, updates an error message, and adds a compile_error if no backends are enabled. --- Cargo.toml | 2 +- src/bin/wasmer.rs | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 557fade49e3..3d1a6b847d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,7 +74,7 @@ serde = { version = "1", features = ["derive"] } # used by the plugin example typetag = "0.1" # used by the plugin example [features] -default = ["fast-tests", "wasi"] +default = ["fast-tests", "wasi", "backend-cranelift"] "loader-kernel" = ["wasmer-kernel-loader"] debug = ["wasmer-runtime-core/debug"] trace = ["wasmer-runtime-core/trace"] diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 457b6f51060..595c135022e 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -40,6 +40,13 @@ use wasmer_runtime_core::{ #[cfg(feature = "wasi")] use wasmer_wasi; +#[cfg(all( + not(feature = "backend-cranelift"), + not(feature = "backend-llvm"), + not(feature = "backend-singlepass") +))] +compile_error!("Please enable at least one of the compiler backends"); + #[derive(Debug, StructOpt)] #[structopt(name = "wasmer", about = "Wasm execution runtime.", author)] /// The options for the wasmer Command Line Interface @@ -560,7 +567,12 @@ fn execute_wasm(options: &Run) -> Result<(), String> { let compiler: Box = match get_compiler_by_backend(options.backend, options) { Some(x) => x, - None => return Err("the requested backend is not enabled".into()), + None => { + return Err(format!( + "the requested backend, \"{}\", is not enabled", + options.backend.to_string() + )) + } }; #[cfg(feature = "backend-llvm")] From 356720efd2068c8883e0b12f9b532d6ceaaf0a4c Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 2 Dec 2019 16:53:15 -0800 Subject: [PATCH 293/342] Add experimental invoke support to WASI in wasmer cli --- src/bin/wasmer.rs | 72 +++++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 457b6f51060..2cf9108d9fa 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -230,6 +230,23 @@ struct Run { args: Vec, } +impl Run { + /// Used with the `invoke` argument + fn parse_args(&self) -> Result, String> { + let mut args: Vec = Vec::new(); + for arg in self.args.iter() { + let x = arg.as_str().parse().map_err(|_| { + format!( + "Can't parse the provided argument {:?} as a integer", + arg.as_str() + ) + })?; + args.push(Value::I32(x)); + } + Ok(args) + } +} + #[allow(dead_code)] #[derive(Debug, Copy, Clone)] enum LoaderName { @@ -448,28 +465,38 @@ fn execute_wasi( let result; #[cfg(unix)] - { - let cv_pushed = - if let Some(msm) = instance.module.runnable_module.get_module_state_map() { - push_code_version(CodeVersion { - baseline: true, - msm: msm, - base: instance.module.runnable_module.get_code().unwrap().as_ptr() as usize, - backend: options.backend, - }); - true - } else { - false - }; + let cv_pushed = if let Some(msm) = instance.module.runnable_module.get_module_state_map() { + push_code_version(CodeVersion { + baseline: true, + msm: msm, + base: instance.module.runnable_module.get_code().unwrap().as_ptr() as usize, + backend: options.backend, + }); + true + } else { + false + }; + + if let Some(invoke_fn) = options.invoke.as_ref() { + eprintln!("WARNING: Invoking a function with WASI is not officially supported in the WASI standard yet. Use this feature at your own risk, things may not work!"); + let args = options.parse_args()?; + let invoke_result = instance + .dyn_func(invoke_fn) + .map_err(|e| format!("Invoke failed: {:?}", e))? + .call(&args) + .map_err(|e| format!("Calling invoke fn failed: {:?}", e))?; + println!("{} returned {:?}", invoke_fn, invoke_result); + return Ok(()); + } else { result = start.call(); + } + + #[cfg(unix)] + { if cv_pushed { pop_code_version().unwrap(); } } - #[cfg(not(unix))] - { - result = start.call(); - } if let Err(ref err) = result { match err { @@ -755,16 +782,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { .instantiate(&import_object) .map_err(|e| format!("Can't instantiate module: {:?}", e))?; - let mut args: Vec = Vec::new(); - for arg in options.args.iter() { - let x = arg.as_str().parse().map_err(|_| { - format!( - "Can't parse the provided argument {:?} as a integer", - arg.as_str() - ) - })?; - args.push(Value::I32(x)); - } + let args = options.parse_args()?; let invoke_fn = match options.invoke.as_ref() { Some(fun) => fun, From 3381e8867cba3dfc8a53fecf6477366e956ab3ff Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 2 Dec 2019 16:51:49 -0800 Subject: [PATCH 294/342] 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 ); } } From 2b7f0d19cbe513f29416695449a91509c5eeded3 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 4 Dec 2019 13:29:28 +0100 Subject: [PATCH 295/342] feat(wasi) Introduce a strict mode for `get_wasi_version`. In strict mode, `get_wasi_version` uses the previous behavior, i.e. it checks that there is only one namespace for all imports, and that this namespace is a WASI namespace (and uses it to find the WASI version). In non-strict mode, `get_wasi_version` checks that at least one WASI namespace exists (and uses it to find the WASI version). By default, `is_wasi_module` uses the non-strict mode. --- lib/wasi/src/utils.rs | 54 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/lib/wasi/src/utils.rs b/lib/wasi/src/utils.rs index e7c24aff48f..562a47e7127 100644 --- a/lib/wasi/src/utils.rs +++ b/lib/wasi/src/utils.rs @@ -4,7 +4,7 @@ use wasmer_runtime_core::module::Module; /// Check if a provided module is compiled for some version of WASI. /// Use [`get_wasi_version`] to find out which version of WASI the module is. pub fn is_wasi_module(module: &Module) -> bool { - get_wasi_version(module).is_some() + get_wasi_version(module, false).is_some() } /// The version of WASI. This is determined by the namespace string @@ -16,21 +16,53 @@ pub enum WasiVersion { Snapshot1, } -/// Detect the version of WASI being used from the namespace -pub fn get_wasi_version(module: &Module) -> Option { - let namespace_table = &module.info().namespace_table; +/// Namespace for the `Snapshot0` version. +const SNAPSHOT0_NAMESPACE: &'static str = "wasi_unstable"; - module - .info() - .imported_functions - .iter() - .find_map(|(_, import_name)| { +/// Namespace for the `Snapshot1` version. +const SNAPSHOT1_NAMESPACE: &'static str = "wasi_snapshot_preview1"; + +/// Detect the version of WASI being used based on the import +/// namespaces. +/// +/// A strict detection expects that all imports live in a single WASI +/// namespace. A non-strict detection expects that at least one WASI +/// namespace exits to detect the version. Note that the strict +/// detection is faster than the non-strict one. +pub fn get_wasi_version(module: &Module, strict: bool) -> Option { + let module_info = &module.info(); + let mut imports = module_info.imported_functions.iter(); + + if strict { + let mut imports = imports.map(|(_, import_name)| import_name.namespace_index); + + // Returns `None` if empty. + let first = imports.next()?; + + // If there is only one namespace… + if imports.all(|index| index == first) { + // … and that this namespace is a WASI one. + match module_info.namespace_table.get(first) { + SNAPSHOT0_NAMESPACE => Some(WasiVersion::Snapshot0), + SNAPSHOT1_NAMESPACE => Some(WasiVersion::Snapshot1), + _ => None, + } + } else { + None + } + } else { + let namespace_table = &module_info.namespace_table; + + // Check that at least a WASI namespace exists, and use the + // first one in the list to detect the WASI version. + imports.find_map(|(_, import_name)| { let namespace_index = import_name.namespace_index; match namespace_table.get(namespace_index) { - "wasi_unstable" => Some(WasiVersion::Snapshot0), - "wasi_snapshot_preview1" => Some(WasiVersion::Snapshot1), + SNAPSHOT0_NAMESPACE => Some(WasiVersion::Snapshot0), + SNAPSHOT1_NAMESPACE => Some(WasiVersion::Snapshot1), _ => None, } }) + } } From 0a24133aabd15b8b31631b8a44e11eec981eb7ff Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 4 Dec 2019 13:34:25 +0100 Subject: [PATCH 296/342] doc(changelog) Update #1028 description. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79f9da5aa5c..634ed0fb042 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## **[Unreleased]** -- [#1028](https://github.com/wasmerio/wasmer/pull/1028) Fix `get_wasi_version` when a module has multiple import namespaces. +- [#1028](https://github.com/wasmerio/wasmer/pull/1028) Introduce strict/non-strict modes for `get_wasi_version` - [#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. - [#1004](https://github.com/wasmerio/wasmer/pull/1004) Add the Auto backend to enable to adapt backend usage depending on wasm file executed. From c12dd859bbc3077bb358bd74a348d921a154d4b0 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 4 Dec 2019 14:12:30 +0100 Subject: [PATCH 297/342] doc(wasi) Improve documentation of `WasiVersion::Latest`. --- lib/wasi/src/utils.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/wasi/src/utils.rs b/lib/wasi/src/utils.rs index 9774abe20e8..d57510eb5f3 100644 --- a/lib/wasi/src/utils.rs +++ b/lib/wasi/src/utils.rs @@ -15,7 +15,17 @@ pub enum WasiVersion { Snapshot0, /// `wasi_snapshot_preview1`. Snapshot1, - /// Latest version (for the moment, an alias to `Snapshot1`). + + /// Latest version. + /// + /// It's a “floating” version, i.e. it's an alias to the latest + /// version (for the moment, `Snapshot1`). Using this version is a + /// way to ensure that modules will run only if they come with the + /// latest WASI version (in case of security issues for instance), + /// by just updating the runtime. + /// + /// Note that this version is never returned by an API. It is + /// provided only by the user. Latest, } From fdc3d5107aa100074645da72b8431042dbbe594d Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 2 Dec 2019 15:58:23 +0100 Subject: [PATCH 298/342] doc(runtime-c-api) Suggest to test in release mode. --- 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 06e545bf739..39e2c21a9fa 100644 --- a/lib/runtime-c-api/README.md +++ b/lib/runtime-c-api/README.md @@ -112,7 +112,7 @@ rebuild in release mode for the tests to see the changes. The tests can be run via `cargo test`, such as: ```sh -$ cargo test -- --nocapture +$ cargo test --release -- --nocapture ``` To run tests manually, enter the `lib/runtime-c-api/tests` directory From ca4a1b41a66fbfbcd5466826a47a19e8aab74369 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 2 Dec 2019 15:59:20 +0100 Subject: [PATCH 299/342] feat(runtime-c-api) Ability to generate `ImportObject` for a specific WASI version. This patch introduces 2 new functions: * `wasmer_wasi_generate_import_object_for_version` and * `wasmer_wasi_get_version`. It mimics the current API provided by `wasmer_wasi`, nothing fancy here. It's just a regular port to C/C++. Because `wasmer_wasi::get_wasi_version` returns an option, and in order to simplify the C/C++ API, `wasmer_wasi_get_version` can return `Version::Unknown` in case of an error. It's up to the user to check the version is valid (i.e. not unknown). --- lib/runtime-c-api/src/import/wasi.rs | 91 ++++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 12 deletions(-) diff --git a/lib/runtime-c-api/src/import/wasi.rs b/lib/runtime-c-api/src/import/wasi.rs index 3df3c7f700b..ec362fdf2ec 100644 --- a/lib/runtime-c-api/src/import/wasi.rs +++ b/lib/runtime-c-api/src/import/wasi.rs @@ -1,6 +1,18 @@ use super::*; use crate::get_slice_checked; -use std::path::PathBuf; +use std::{path::PathBuf, ptr, str}; +use wasmer_wasi as wasi; + +#[derive(Debug)] +#[repr(u8)] +pub enum Version { + /// Version cannot be detected or is unknown. + Unknown, + /// `wasi_unstable`. + Snapshot0, + /// `wasi_snapshot_preview1`. + Snapshot1, +} /// Opens a directory that's visible to the WASI module as `alias` but /// is backed by the host file at `host_file_path` @@ -14,9 +26,9 @@ pub struct wasmer_wasi_map_dir_entry_t { 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> { + pub unsafe fn as_tuple(&self) -> Result<(String, PathBuf), str::Utf8Error> { let alias = self.alias.as_str()?.to_owned(); - let host_path = std::path::PathBuf::from(self.host_file_path.as_str()?); + let host_path = PathBuf::from(self.host_file_path.as_str()?); Ok((alias, host_path)) } @@ -44,21 +56,74 @@ pub unsafe extern "C" fn wasmer_wasi_generate_import_object( let mapped_dir_list = get_slice_checked(mapped_dirs, mapped_dirs_len as usize); wasmer_wasi_generate_import_object_inner( + Version::Snapshot1, arg_list, env_list, preopened_file_list, mapped_dir_list, ) - .unwrap_or(std::ptr::null_mut()) + .unwrap_or(ptr::null_mut()) +} + +/// Creates a WASI import object. +/// +/// This function is similar to `wasmer_wasi_generate_import_object` +/// except that the first argument describes the WASI version. +#[no_mangle] +pub unsafe extern "C" fn wasmer_wasi_generate_import_object_for_version( + version: Version, + 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( + version, + arg_list, + env_list, + preopened_file_list, + mapped_dir_list, + ) + .unwrap_or(ptr::null_mut()) +} + +/// Find the version of WASI used by the module. +/// +/// In case of error, the returned version is `Version::Unknown`. +#[no_mangle] +pub unsafe extern "C" fn wasmer_wasi_get_version(module: *const wasmer_module_t) -> Version { + if module.is_null() { + return Version::Unknown; + } + + let module = &*(module as *const Module); + + match wasi::get_wasi_version(module) { + Some(version) => match version { + wasi::WasiVersion::Snapshot0 => Version::Snapshot0, + wasi::WasiVersion::Snapshot1 => Version::Snapshot1, + }, + None => Version::Unknown, + } } /// Inner function that wraps error handling fn wasmer_wasi_generate_import_object_inner( + version: Version, 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> { +) -> Result<*mut wasmer_import_object_t, str::Utf8Error> { let arg_vec = arg_list.iter().map(|arg| unsafe { arg.as_vec() }).collect(); let env_vec = env_list .iter() @@ -73,7 +138,14 @@ fn wasmer_wasi_generate_import_object_inner( .map(|entry| unsafe { entry.as_tuple() }) .collect::, _>>()?; - let import_object = Box::new(wasmer_wasi::generate_import_object( + let version = match version { + Version::Snapshot0 => wasi::WasiVersion::Snapshot0, + Version::Snapshot1 => wasi::WasiVersion::Snapshot1, + _ => panic!(format!("Version {:?} is invalid.", version)), + }; + + let import_object = Box::new(wasi::generate_import_object_for_version( + version, arg_vec, env_vec, po_file_vec, @@ -90,12 +162,7 @@ fn wasmer_wasi_generate_import_object_inner( #[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![], - )); + let import_object = Box::new(wasi::generate_import_object(vec![], vec![], vec![], vec![])); Box::into_raw(import_object) as *mut wasmer_import_object_t } From e2c353b926ad4e46a8b3a10289188ca021501255 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 2 Dec 2019 16:05:01 +0100 Subject: [PATCH 300/342] chore(runtime-c-api) Update C/C++ headers. --- lib/runtime-c-api/wasmer.h | 39 +++++++++++++++++++++++++++++++++++++ lib/runtime-c-api/wasmer.hh | 28 ++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 40a265cff3b..672a1704cd5 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -25,6 +25,22 @@ #include #include +enum Version { + /** + * Version cannot be detected or is unknown. + */ + Unknown, + /** + * `wasi_unstable`. + */ + Snapshot0, + /** + * `wasi_snapshot_preview1`. + */ + Snapshot1, +}; +typedef uint8_t Version; + /** * List of export/import kinds. */ @@ -890,4 +906,27 @@ wasmer_import_object_t *wasmer_wasi_generate_import_object(const wasmer_byte_arr const wasmer_wasi_map_dir_entry_t *mapped_dirs, unsigned int mapped_dirs_len); +/** + * Creates a WASI import object. + * + * This function is similar to `wasmer_wasi_generate_import_object` + * except that the first argument describes the WASI version. + */ +wasmer_import_object_t *wasmer_wasi_generate_import_object_for_version(Version version, + 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); + +/** + * Find the version of WASI used by the module. + * + * In case of error, the returned version is `Version::Unknown`. + */ +Version wasmer_wasi_get_version(const wasmer_module_t *module); + #endif /* WASMER_H */ diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index b437edd4be0..d293c817ebc 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -25,6 +25,15 @@ #include #include +enum class Version : uint8_t { + /// Version cannot be detected or is unknown. + Unknown, + /// `wasi_unstable`. + Snapshot0, + /// `wasi_snapshot_preview1`. + Snapshot1, +}; + /// List of export/import kinds. enum class wasmer_import_export_kind : uint32_t { WASM_FUNCTION = 0, @@ -702,6 +711,25 @@ wasmer_import_object_t *wasmer_wasi_generate_import_object(const wasmer_byte_arr const wasmer_wasi_map_dir_entry_t *mapped_dirs, unsigned int mapped_dirs_len); +/// Creates a WASI import object. +/// +/// This function is similar to `wasmer_wasi_generate_import_object` +/// except that the first argument describes the WASI version. +wasmer_import_object_t *wasmer_wasi_generate_import_object_for_version(Version version, + 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); + +/// Find the version of WASI used by the module. +/// +/// In case of error, the returned version is `Version::Unknown`. +Version wasmer_wasi_get_version(const wasmer_module_t *module); + } // extern "C" #endif // WASMER_H From 7fb934f5d09452935d4e9628a5b634e8ad6f03c5 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 2 Dec 2019 16:05:34 +0100 Subject: [PATCH 301/342] chore(runtime-c-api) Fix CS in `CMakeLists.txt`. --- lib/runtime-c-api/tests/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/runtime-c-api/tests/CMakeLists.txt b/lib/runtime-c-api/tests/CMakeLists.txt index e4a573e6386..20f7dea13bd 100644 --- a/lib/runtime-c-api/tests/CMakeLists.txt +++ b/lib/runtime-c-api/tests/CMakeLists.txt @@ -19,12 +19,12 @@ add_executable(test-context test-context.c) add_executable(test-module-import-instantiate test-module-import-instantiate.c) if (DEFINED WASI_TESTS) - add_executable(test-wasi-import-object test-wasi-import-object.c) + add_executable(test-wasi-import-object test-wasi-import-object.c) endif() find_library( - WASMER_LIB NAMES libwasmer_runtime_c_api.dylib libwasmer_runtime_c_api.so wasmer_runtime_c_api.dll - PATHS ${CMAKE_SOURCE_DIR}/../../../target/release/ + WASMER_LIB NAMES libwasmer_runtime_c_api.dylib libwasmer_runtime_c_api.so wasmer_runtime_c_api.dll + PATHS ${CMAKE_SOURCE_DIR}/../../../target/release/ ) if(NOT WASMER_LIB) From 0391ade76f0d1a7abd8099279154ecc256a320a1 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 2 Dec 2019 16:07:20 +0100 Subject: [PATCH 302/342] chore(git) Ignore the object file `test-import-object`. --- lib/runtime-c-api/tests/.gitignore | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/runtime-c-api/tests/.gitignore b/lib/runtime-c-api/tests/.gitignore index b64fa610c7e..cbc7f3b1fcf 100644 --- a/lib/runtime-c-api/tests/.gitignore +++ b/lib/runtime-c-api/tests/.gitignore @@ -10,20 +10,20 @@ compile_commands.json CTestTestfile.cmake _deps rust-build +test-context test-exported-memory test-exports test-globals test-import-function +test-import-object test-imports test-instantiate test-memory test-module test-module-exports +test-module-import-instantiate test-module-imports test-module-serialize test-tables test-validate -test-context -test-module-import-instantiate -test-wasi-import-object - +test-wasi-import-object \ No newline at end of file From 912713f88fc51122627a65f05cfbdb0566f9e218 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 2 Dec 2019 16:09:14 +0100 Subject: [PATCH 303/342] test(runtime-c-api) Test the new WASI version API. This patch updates `test-wasi-import-object` to test the new `wasmer_wasi_get_version` & `wasmer_wasi_generate_import_object_for_version` functions, and the new `Version` type. --- .../tests/test-wasi-import-object.c | 44 ++++++++++++------- 1 file changed, 27 insertions(+), 17 deletions(-) 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 bd1478dc137..da94849963e 100644 --- a/lib/runtime-c-api/tests/test-wasi-import-object.c +++ b/lib/runtime-c-api/tests/test-wasi-import-object.c @@ -28,9 +28,9 @@ void print_wasmer_error() // 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]); - } + for (int i = 0; i < arr->bytes_len; ++i) { + putchar(arr->bytes[i]); + } } int main() @@ -164,20 +164,7 @@ int main() }; 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 + // Read the Wasm file bytes. FILE *file = fopen("assets/extended_wasi.wasm", "r"); assert(file); fseek(file, 0, SEEK_END); @@ -191,16 +178,39 @@ int main() // 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); + // Detect the WASI version if any. This step is not mandatory, we + // use it to test the WASI version API. + Version wasi_version = wasmer_wasi_get_version(module); + + printf("WASI version: %d\n", wasi_version); + + // Create the WASI import object + wasmer_import_object_t *import_object = + wasmer_wasi_generate_import_object_for_version(wasi_version, + 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); + // 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(); From b9851f26d45de4a0e9fd9c8af43716257c76a9f5 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 2 Dec 2019 16:19:19 +0100 Subject: [PATCH 304/342] doc(changelog) Add #1030. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 266dd165d34..b339615c989 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ - [#1028](https://github.com/wasmerio/wasmer/pull/1028) Introduce strict/non-strict modes for `get_wasi_version` - [#1029](https://github.com/wasmerio/wasmer/pull/1029) Add the “floating” `WasiVersion::Latest` version. +- [#1030](https://github.com/wasmerio/wasmer/pull/1030) Ability to generate `ImportObject` for a specific version WASI version with the C API. +- [#1028](https://github.com/wasmerio/wasmer/pull/1028) Fix `get_wasi_version` when a module has multiple import namespaces. - [#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. From 4fe8286b8197ebc4174553343aebae1930241157 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 4 Dec 2019 14:33:10 +0100 Subject: [PATCH 305/342] feat(runtime-c-api) Avoid undefined behavior with user-given version. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the version has type `Version`, we expect the user to give a valid `Version` variant. Since the `Version` is basically a `uint8_t`, the user is able to pass everything she wants, which can create an undefined behavior on the Rust side. To avoid such situation, the version has now type `c_uchar` (`unsigned char` or `uint8_t` on C side —on most platforms). Then the `From` trait is implemented on `Version`. In case the value is unbound, `Version::Unknown` is returned. --- lib/runtime-c-api/src/import/mod.rs | 2 +- lib/runtime-c-api/src/import/wasi.rs | 14 ++++++++++++-- lib/runtime-c-api/wasmer.h | 2 +- lib/runtime-c-api/wasmer.hh | 2 +- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/runtime-c-api/src/import/mod.rs b/lib/runtime-c-api/src/import/mod.rs index 5b44eb2b557..2bca1e3902c 100644 --- a/lib/runtime-c-api/src/import/mod.rs +++ b/lib/runtime-c-api/src/import/mod.rs @@ -8,7 +8,7 @@ use crate::{ value::wasmer_value_tag, wasmer_byte_array, wasmer_result_t, }; -use libc::c_uint; +use libc::{c_uchar, c_uint}; use std::{convert::TryFrom, ffi::c_void, ptr, slice, sync::Arc}; use wasmer_runtime::{Global, Memory, Module, Table}; use wasmer_runtime_core::{ diff --git a/lib/runtime-c-api/src/import/wasi.rs b/lib/runtime-c-api/src/import/wasi.rs index ec362fdf2ec..2f105b1a1d3 100644 --- a/lib/runtime-c-api/src/import/wasi.rs +++ b/lib/runtime-c-api/src/import/wasi.rs @@ -14,6 +14,16 @@ pub enum Version { Snapshot1, } +impl From for Version { + fn from(value: c_uchar) -> Self { + match value { + 0 => Self::Snapshot0, + 1 => Self::Snapshot1, + _ => Self::Unknown, + } + } +} + /// 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)] @@ -71,7 +81,7 @@ pub unsafe extern "C" fn wasmer_wasi_generate_import_object( /// except that the first argument describes the WASI version. #[no_mangle] pub unsafe extern "C" fn wasmer_wasi_generate_import_object_for_version( - version: Version, + version: c_uchar, args: *const wasmer_byte_array, args_len: c_uint, envs: *const wasmer_byte_array, @@ -87,7 +97,7 @@ pub unsafe extern "C" fn wasmer_wasi_generate_import_object_for_version( let mapped_dir_list = get_slice_checked(mapped_dirs, mapped_dirs_len as usize); wasmer_wasi_generate_import_object_inner( - version, + version.into(), arg_list, env_list, preopened_file_list, diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 672a1704cd5..09d716e8ab5 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -912,7 +912,7 @@ wasmer_import_object_t *wasmer_wasi_generate_import_object(const wasmer_byte_arr * This function is similar to `wasmer_wasi_generate_import_object` * except that the first argument describes the WASI version. */ -wasmer_import_object_t *wasmer_wasi_generate_import_object_for_version(Version version, +wasmer_import_object_t *wasmer_wasi_generate_import_object_for_version(unsigned char version, const wasmer_byte_array *args, unsigned int args_len, const wasmer_byte_array *envs, diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index d293c817ebc..aac8daec312 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -715,7 +715,7 @@ wasmer_import_object_t *wasmer_wasi_generate_import_object(const wasmer_byte_arr /// /// This function is similar to `wasmer_wasi_generate_import_object` /// except that the first argument describes the WASI version. -wasmer_import_object_t *wasmer_wasi_generate_import_object_for_version(Version version, +wasmer_import_object_t *wasmer_wasi_generate_import_object_for_version(unsigned char version, const wasmer_byte_array *args, unsigned int args_len, const wasmer_byte_array *envs, From 0c5021484f680db913689bf6a720040fe319c32f Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 4 Dec 2019 14:37:13 +0100 Subject: [PATCH 306/342] fix(runtime-c-api) Use `get_wasi_version` in non-strict mode. --- lib/runtime-c-api/src/import/wasi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime-c-api/src/import/wasi.rs b/lib/runtime-c-api/src/import/wasi.rs index 2f105b1a1d3..9b63a96a1f6 100644 --- a/lib/runtime-c-api/src/import/wasi.rs +++ b/lib/runtime-c-api/src/import/wasi.rs @@ -117,7 +117,7 @@ pub unsafe extern "C" fn wasmer_wasi_get_version(module: *const wasmer_module_t) let module = &*(module as *const Module); - match wasi::get_wasi_version(module) { + match wasi::get_wasi_version(module, false) { Some(version) => match version { wasi::WasiVersion::Snapshot0 => Version::Snapshot0, wasi::WasiVersion::Snapshot1 => Version::Snapshot1, From 90f3c894c110cbe27c69494ac8c64347ae19fa14 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 4 Dec 2019 14:38:54 +0100 Subject: [PATCH 307/342] doc(runtime-c-api) Improve documentation of `wasmer_wasi_generate_import_object_for_version`. --- lib/runtime-c-api/src/import/wasi.rs | 4 +++- lib/runtime-c-api/wasmer.h | 4 +++- lib/runtime-c-api/wasmer.hh | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/runtime-c-api/src/import/wasi.rs b/lib/runtime-c-api/src/import/wasi.rs index 9b63a96a1f6..46caab24880 100644 --- a/lib/runtime-c-api/src/import/wasi.rs +++ b/lib/runtime-c-api/src/import/wasi.rs @@ -75,10 +75,12 @@ pub unsafe extern "C" fn wasmer_wasi_generate_import_object( .unwrap_or(ptr::null_mut()) } -/// Creates a WASI import object. +/// Creates a WASI import object for a specific version. /// /// This function is similar to `wasmer_wasi_generate_import_object` /// except that the first argument describes the WASI version. +/// +/// The version is expected to be of kind `Version`. #[no_mangle] pub unsafe extern "C" fn wasmer_wasi_generate_import_object_for_version( version: c_uchar, diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 09d716e8ab5..282a6ee05d4 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -907,10 +907,12 @@ wasmer_import_object_t *wasmer_wasi_generate_import_object(const wasmer_byte_arr unsigned int mapped_dirs_len); /** - * Creates a WASI import object. + * Creates a WASI import object for a specific version. * * This function is similar to `wasmer_wasi_generate_import_object` * except that the first argument describes the WASI version. + * + * The version is expected to be of kind `Version`. */ wasmer_import_object_t *wasmer_wasi_generate_import_object_for_version(unsigned char version, const wasmer_byte_array *args, diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index aac8daec312..a78780118d0 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -711,10 +711,12 @@ wasmer_import_object_t *wasmer_wasi_generate_import_object(const wasmer_byte_arr const wasmer_wasi_map_dir_entry_t *mapped_dirs, unsigned int mapped_dirs_len); -/// Creates a WASI import object. +/// Creates a WASI import object for a specific version. /// /// This function is similar to `wasmer_wasi_generate_import_object` /// except that the first argument describes the WASI version. +/// +/// The version is expected to be of kind `Version`. wasmer_import_object_t *wasmer_wasi_generate_import_object_for_version(unsigned char version, const wasmer_byte_array *args, unsigned int args_len, From 345511a4f9800e63611ec8ffbac3fa08c73884b2 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 4 Dec 2019 14:48:12 +0100 Subject: [PATCH 308/342] fix(runtime-c-api) Fix `From for Version`. 0 matches to `Unknown`, 1 matches to `Snapshot0` and 2 matches to `Snapshot1`. --- lib/runtime-c-api/src/import/wasi.rs | 24 ++++++++++++++++++------ lib/runtime-c-api/wasmer.h | 6 +++--- lib/runtime-c-api/wasmer.hh | 6 +++--- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/lib/runtime-c-api/src/import/wasi.rs b/lib/runtime-c-api/src/import/wasi.rs index 46caab24880..2766cb83cba 100644 --- a/lib/runtime-c-api/src/import/wasi.rs +++ b/lib/runtime-c-api/src/import/wasi.rs @@ -3,22 +3,22 @@ use crate::get_slice_checked; use std::{path::PathBuf, ptr, str}; use wasmer_wasi as wasi; -#[derive(Debug)] +#[derive(Debug, PartialEq)] #[repr(u8)] pub enum Version { /// Version cannot be detected or is unknown. - Unknown, + Unknown = 0, /// `wasi_unstable`. - Snapshot0, + Snapshot0 = 1, /// `wasi_snapshot_preview1`. - Snapshot1, + Snapshot1 = 2, } impl From for Version { fn from(value: c_uchar) -> Self { match value { - 0 => Self::Snapshot0, - 1 => Self::Snapshot1, + 1 => Self::Snapshot0, + 2 => Self::Snapshot1, _ => Self::Unknown, } } @@ -178,3 +178,15 @@ pub unsafe extern "C" fn wasmer_wasi_generate_default_import_object() -> *mut wa Box::into_raw(import_object) as *mut wasmer_import_object_t } + +#[cfg(test)] +mod tests { + use super::Version; + + #[test] + fn test_versions_from_uint() { + assert_eq!(Version::Unknown, 0.into()); + assert_eq!(Version::Snapshot0, 1.into()); + assert_eq!(Version::Snapshot1, 2.into()); + } +} diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 282a6ee05d4..1440b16dcd9 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -29,15 +29,15 @@ enum Version { /** * Version cannot be detected or is unknown. */ - Unknown, + Unknown = 0, /** * `wasi_unstable`. */ - Snapshot0, + Snapshot0 = 1, /** * `wasi_snapshot_preview1`. */ - Snapshot1, + Snapshot1 = 2, }; typedef uint8_t Version; diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index a78780118d0..5366ee88d41 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -27,11 +27,11 @@ enum class Version : uint8_t { /// Version cannot be detected or is unknown. - Unknown, + Unknown = 0, /// `wasi_unstable`. - Snapshot0, + Snapshot0 = 1, /// `wasi_snapshot_preview1`. - Snapshot1, + Snapshot1 = 2, }; /// List of export/import kinds. From 4fc6adf9c28bd387fe7f394a0cae3b1d0d303106 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 4 Dec 2019 14:51:29 +0100 Subject: [PATCH 309/342] chore(runtime-c-api) Remove a useless `format!`. --- lib/runtime-c-api/src/import/wasi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime-c-api/src/import/wasi.rs b/lib/runtime-c-api/src/import/wasi.rs index 2766cb83cba..6d7e6a52352 100644 --- a/lib/runtime-c-api/src/import/wasi.rs +++ b/lib/runtime-c-api/src/import/wasi.rs @@ -153,7 +153,7 @@ fn wasmer_wasi_generate_import_object_inner( let version = match version { Version::Snapshot0 => wasi::WasiVersion::Snapshot0, Version::Snapshot1 => wasi::WasiVersion::Snapshot1, - _ => panic!(format!("Version {:?} is invalid.", version)), + _ => panic!("Version {:?} is invalid.", version), }; let import_object = Box::new(wasi::generate_import_object_for_version( From f0f0657264bfce83d7ffc17ab7884a3ba1c511aa Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 4 Dec 2019 14:52:58 +0100 Subject: [PATCH 310/342] doc(changelog) Resolve merge issues. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b339615c989..fc2ad7754ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ - [#1028](https://github.com/wasmerio/wasmer/pull/1028) Introduce strict/non-strict modes for `get_wasi_version` - [#1029](https://github.com/wasmerio/wasmer/pull/1029) Add the “floating” `WasiVersion::Latest` version. - [#1030](https://github.com/wasmerio/wasmer/pull/1030) Ability to generate `ImportObject` for a specific version WASI version with the C API. -- [#1028](https://github.com/wasmerio/wasmer/pull/1028) Fix `get_wasi_version` when a module has multiple import namespaces. +- [#1028](https://github.com/wasmerio/wasmer/pull/1028) Introduce strict/non-strict modes for `get_wasi_version` - [#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. From 4ef799f23d6f86e2533cd254374cb39320faddeb Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 4 Dec 2019 15:34:56 +0100 Subject: [PATCH 311/342] feat(runtime-c-api) Support `WasiVersion::Latest`. --- CHANGELOG.md | 2 +- lib/runtime-c-api/src/import/wasi.rs | 24 +++++++++++++++++------- lib/runtime-c-api/wasmer.h | 9 +++++++-- lib/runtime-c-api/wasmer.hh | 7 +++++-- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc2ad7754ea..495361d2876 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,9 @@ ## **[Unreleased]** +- [#1030](https://github.com/wasmerio/wasmer/pull/1030) Ability to generate `ImportObject` for a specific version WASI version with the C API. - [#1028](https://github.com/wasmerio/wasmer/pull/1028) Introduce strict/non-strict modes for `get_wasi_version` - [#1029](https://github.com/wasmerio/wasmer/pull/1029) Add the “floating” `WasiVersion::Latest` version. -- [#1030](https://github.com/wasmerio/wasmer/pull/1030) Ability to generate `ImportObject` for a specific version WASI version with the C API. - [#1028](https://github.com/wasmerio/wasmer/pull/1028) Introduce strict/non-strict modes for `get_wasi_version` - [#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. diff --git a/lib/runtime-c-api/src/import/wasi.rs b/lib/runtime-c-api/src/import/wasi.rs index 6d7e6a52352..0ff833a61f5 100644 --- a/lib/runtime-c-api/src/import/wasi.rs +++ b/lib/runtime-c-api/src/import/wasi.rs @@ -8,17 +8,24 @@ use wasmer_wasi as wasi; pub enum Version { /// Version cannot be detected or is unknown. Unknown = 0, + + /// Latest version. See `wasmer_wasi::WasiVersion::Latest` to + /// leran more. + Latest = 1, + /// `wasi_unstable`. - Snapshot0 = 1, + Snapshot0 = 2, + /// `wasi_snapshot_preview1`. - Snapshot1 = 2, + Snapshot1 = 3, } impl From for Version { fn from(value: c_uchar) -> Self { match value { - 1 => Self::Snapshot0, - 2 => Self::Snapshot1, + 1 => Self::Latest, + 2 => Self::Snapshot0, + 3 => Self::Snapshot1, _ => Self::Unknown, } } @@ -66,7 +73,7 @@ pub unsafe extern "C" fn wasmer_wasi_generate_import_object( let mapped_dir_list = get_slice_checked(mapped_dirs, mapped_dirs_len as usize); wasmer_wasi_generate_import_object_inner( - Version::Snapshot1, + Version::Latest, arg_list, env_list, preopened_file_list, @@ -123,6 +130,7 @@ pub unsafe extern "C" fn wasmer_wasi_get_version(module: *const wasmer_module_t) Some(version) => match version { wasi::WasiVersion::Snapshot0 => Version::Snapshot0, wasi::WasiVersion::Snapshot1 => Version::Snapshot1, + wasi::WasiVersion::Latest => Version::Latest, }, None => Version::Unknown, } @@ -151,6 +159,7 @@ fn wasmer_wasi_generate_import_object_inner( .collect::, _>>()?; let version = match version { + Version::Latest => wasi::WasiVersion::Latest, Version::Snapshot0 => wasi::WasiVersion::Snapshot0, Version::Snapshot1 => wasi::WasiVersion::Snapshot1, _ => panic!("Version {:?} is invalid.", version), @@ -186,7 +195,8 @@ mod tests { #[test] fn test_versions_from_uint() { assert_eq!(Version::Unknown, 0.into()); - assert_eq!(Version::Snapshot0, 1.into()); - assert_eq!(Version::Snapshot1, 2.into()); + assert_eq!(Version::Latest, 1.into()); + assert_eq!(Version::Snapshot0, 2.into()); + assert_eq!(Version::Snapshot1, 3.into()); } } diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 1440b16dcd9..de921e3b04d 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -30,14 +30,19 @@ enum Version { * Version cannot be detected or is unknown. */ Unknown = 0, + /** + * Latest version. See `wasmer_wasi::WasiVersion::Latest` to + * leran more. + */ + Latest = 1, /** * `wasi_unstable`. */ - Snapshot0 = 1, + Snapshot0 = 2, /** * `wasi_snapshot_preview1`. */ - Snapshot1 = 2, + Snapshot1 = 3, }; typedef uint8_t Version; diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 5366ee88d41..09b58f86100 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -28,10 +28,13 @@ enum class Version : uint8_t { /// Version cannot be detected or is unknown. Unknown = 0, + /// Latest version. See `wasmer_wasi::WasiVersion::Latest` to + /// leran more. + Latest = 1, /// `wasi_unstable`. - Snapshot0 = 1, + Snapshot0 = 2, /// `wasi_snapshot_preview1`. - Snapshot1 = 2, + Snapshot1 = 3, }; /// List of export/import kinds. From af7a3683203083cef0e9d78faf057686811b2be9 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 4 Dec 2019 13:11:11 -0800 Subject: [PATCH 312/342] Added docs to Readme and removed WAPM usage --- README.md | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 6b8ca9d48bf..0391bbd9b97 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,9 @@ Build Status + + Documentation + License @@ -23,7 +26,7 @@ [Wasmer](https://wasmer.io/) is a standalone WebAssembly runtime for running WebAssembly [outside of the browser](https://webassembly.org/docs/non-web/), supporting [WASI](https://github.com/WebAssembly/WASI) and [Emscripten](https://emscripten.org/). Wasmer can be used standalone (via the CLI) and embedded in different languages, running in x86 and [ARM devices](https://medium.com/wasmer/running-webassembly-on-arm-7d365ed0e50c). -Install the Wasmer CLI with: +Install the Wasmer and [WAPM](https://wapm.io) cli with: ```sh curl https://get.wasmer.io -sSfL | sh @@ -59,28 +62,15 @@ Once installed, you will be able to run any WebAssembly files (_including Lua, P ```sh # Run Lua -wasmer run examples/lua.wasm +wasmer examples/lua.wasm ``` *You can find more `wasm/wat` examples in the [examples](./examples) directory.* -#### With wapm - -Installing Wasmer through `wasmer.io` includes -[`wapm`](https://github.com/wasmerio/wapm-cli), the [WebAssembly Package Manager](https://wapm.io/). - -wapm allows you to easily download, run, and distribute WebAssembly binaries. +### Docs -```sh -# Install cowsay globally -wapm install -g cowsay - -# Run cowsay -wapm run cowsay "Hello, world!" -``` +Wasmer documentation lives on [docs.wasmer.io](https://docs.wasmer.io). -For more information about wapm, check out the [website](https://www.wapm.io) -and this [example program](https://github.com/wapm-packages/rust-wasi-example). ## Code Structure @@ -259,8 +249,8 @@ Below are some of the goals of this project (in order of priority): - [x] It should be 100% compatible with the [WebAssembly spec tests](https://github.com/wasmerio/wasmer/tree/master/lib/spectests/spectests) - [x] It should be fast _(partially achieved)_ - [x] Support WASI - released in [0.3.0](https://github.com/wasmerio/wasmer/releases/tag/0.3.0) -- [x] Support Emscripten calls _(in the works)_ -- [ ] Support Go JS ABI calls +- [x] Support Emscripten calls +- [ ] Support Go JS ABI calls _(in the works)_ ## Architecture From 176b938cb617493faa4fff33727eeecda5baa82a Mon Sep 17 00:00:00 2001 From: Mark McCaskey <5770194+MarkMcCaskey@users.noreply.github.com> Date: Thu, 5 Dec 2019 11:59:26 -0800 Subject: [PATCH 313/342] Remove wasmparser dep from singlepass --- lib/singlepass-backend/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/singlepass-backend/Cargo.toml b/lib/singlepass-backend/Cargo.toml index eb292dbcbc7..7b9e424b501 100644 --- a/lib/singlepass-backend/Cargo.toml +++ b/lib/singlepass-backend/Cargo.toml @@ -25,4 +25,4 @@ bincode = "1.2" [features] default = [] -deterministic-execution = ["wasmparser/deterministic", "wasmer-runtime-core/deterministic-execution"] \ No newline at end of file +deterministic-execution = ["wasmer-runtime-core/deterministic-execution"] From d144976da045db011c697a22003948e4736e9b29 Mon Sep 17 00:00:00 2001 From: Mark McCaskey <5770194+MarkMcCaskey@users.noreply.github.com> Date: Thu, 5 Dec 2019 12:01:46 -0800 Subject: [PATCH 314/342] Manually apply formatting to cfg statement --- lib/runtime/src/lib.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index 3febd072c9d..13b3dd8d4e7 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -235,10 +235,13 @@ pub fn default_compiler() -> impl Compiler { #[cfg(all(feature = "default-backend-llvm", not(feature = "docs")))] use wasmer_llvm_backend::LLVMCompiler as DefaultCompiler; - #[cfg(all(any( - feature = "default-backend-singlepass", - all(feature = "deterministic-execution", feature = "singlepass") - ), not(feature = "docs")))] + #[cfg(all( + any( + feature = "default-backend-singlepass", + all(feature = "deterministic-execution", feature = "singlepass") + ), + not(feature = "docs") + ))] use wasmer_singlepass_backend::SinglePassCompiler as DefaultCompiler; #[cfg(any(feature = "default-backend-cranelift", feature = "docs"))] From 8d3cf874cdd8fd603f1021d0d79899a3c7a7b5ee Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Wed, 4 Dec 2019 10:38:28 -0800 Subject: [PATCH 315/342] Add the ability to pass backend specific options through CompilerConfig. Use this to replace wasmer_llvm_backend::GLOBAL_OPTIONS. --- lib/llvm-backend/src/backend.rs | 16 ++++----- lib/llvm-backend/src/code.rs | 21 +++++++++--- lib/llvm-backend/src/lib.rs | 26 +++++--------- lib/runtime-core/src/backend.rs | 17 ++++++++- src/bin/wasmer.rs | 61 +++++++++++++++++++++++++-------- 5 files changed, 95 insertions(+), 46 deletions(-) diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index a5d26203521..468c3fc7c72 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -2,6 +2,7 @@ use super::stackmap::StackmapRegistry; use crate::{ intrinsics::Intrinsics, structs::{Callbacks, LLVMModule, LLVMResult, MemProtect}, + LLVMCallbacks, }; use inkwell::{ memory_buffer::MemoryBuffer, @@ -13,8 +14,6 @@ use std::{ any::Any, cell::RefCell, ffi::{c_void, CString}, - fs::File, - io::Write, mem, ops::Deref, ptr::{self, NonNull}, @@ -176,23 +175,22 @@ impl LLVMBackend { _stackmaps: &StackmapRegistry, _module_info: &ModuleInfo, target_machine: &TargetMachine, + llvm_callbacks: &Option>>, ) -> (Self, LLVMCache) { let memory_buffer = target_machine .write_to_memory_buffer(&module.borrow_mut(), FileType::Object) .unwrap(); - let mem_buf_slice = memory_buffer.as_slice(); - if let Some(path) = unsafe { &crate::GLOBAL_OPTIONS.obj_file } { - let mut file = File::create(path).unwrap(); - let mut pos = 0; - while pos < mem_buf_slice.len() { - pos += file.write(&mem_buf_slice[pos..]).unwrap(); - } + if let Some(callbacks) = llvm_callbacks { + callbacks + .borrow_mut() + .obj_memory_buffer_callback(&memory_buffer); } let callbacks = get_callbacks(); let mut module: *mut LLVMModule = ptr::null_mut(); + let mem_buf_slice = memory_buffer.as_slice(); let res = unsafe { module_load( mem_buf_slice.as_ptr(), diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index c0f6e07dd63..4365dbf3326 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -5,6 +5,7 @@ use crate::{ stackmap::{StackmapEntry, StackmapEntryKind, StackmapRegistry, ValueSemantic}, state::{ControlFrame, ExtraInfo, IfElseState, State}, trampolines::generate_trampolines, + LLVMBackendConfig, LLVMCallbacks, }; use inkwell::{ builder::Builder, @@ -877,6 +878,7 @@ pub struct LLVMModuleCodeGenerator<'ctx> { stackmaps: Rc>, track_state: bool, target_machine: TargetMachine, + llvm_callbacks: Option>>, } pub struct LLVMFunctionCodeGenerator<'ctx> { @@ -8513,6 +8515,7 @@ impl<'ctx> ModuleCodeGenerator, LLVMBackend, Cod stackmaps: Rc::new(RefCell::new(StackmapRegistry::default())), track_state: false, target_machine, + llvm_callbacks: None, } } @@ -8654,8 +8657,10 @@ impl<'ctx> ModuleCodeGenerator, LLVMBackend, Cod message: format!("trampolines generation error: {:?}", e), })?; - if let Some(path) = unsafe { &crate::GLOBAL_OPTIONS.pre_opt_ir } { - self.module.borrow_mut().print_to_file(path).unwrap(); + if let Some(ref mut callbacks) = self.llvm_callbacks { + callbacks + .borrow_mut() + .preopt_ir_callback(&*self.module.borrow_mut()); } let pass_manager = PassManager::create(()); @@ -8695,8 +8700,10 @@ impl<'ctx> ModuleCodeGenerator, LLVMBackend, Cod pass_manager.add_early_cse_pass(); pass_manager.run_on(&*self.module.borrow_mut()); - if let Some(path) = unsafe { &crate::GLOBAL_OPTIONS.post_opt_ir } { - self.module.borrow_mut().print_to_file(path).unwrap(); + if let Some(ref mut callbacks) = self.llvm_callbacks { + callbacks + .borrow_mut() + .postopt_ir_callback(&*self.module.borrow_mut()); } let stackmaps = self.stackmaps.borrow(); @@ -8707,12 +8714,18 @@ impl<'ctx> ModuleCodeGenerator, LLVMBackend, Cod &*stackmaps, module_info, &self.target_machine, + &mut self.llvm_callbacks, ); Ok((backend, Box::new(cache_gen))) } fn feed_compiler_config(&mut self, config: &CompilerConfig) -> Result<(), CodegenError> { self.track_state = config.track_state; + if let Some(backend_compiler_config) = &config.backend_specific_config { + if let Some(llvm_config) = backend_compiler_config.get_specific::() { + self.llvm_callbacks = llvm_config.callbacks.clone(); + } + } Ok(()) } diff --git a/lib/llvm-backend/src/lib.rs b/lib/llvm-backend/src/lib.rs index 2b3f7d2e67c..853cfac1195 100644 --- a/lib/llvm-backend/src/lib.rs +++ b/lib/llvm-backend/src/lib.rs @@ -21,8 +21,6 @@ mod state; mod structs; mod trampolines; -use std::path::PathBuf; - pub use code::LLVMFunctionCodeGenerator as FunctionCodeGenerator; pub use code::LLVMModuleCodeGenerator as ModuleCodeGenerator; @@ -35,21 +33,15 @@ pub type LLVMCompiler = SimpleStreamingCompilerGen< code::CodegenError, >; -#[derive(Debug, Clone)] -/// LLVM backend flags. -pub struct LLVMOptions { - /// Emit LLVM IR before optimization pipeline. - pub pre_opt_ir: Option, - - /// Emit LLVM IR after optimization pipeline. - pub post_opt_ir: Option, +pub type InkwellModule<'ctx> = inkwell::module::Module<'ctx>; +pub type InkwellMemoryBuffer = inkwell::memory_buffer::MemoryBuffer; - /// Emit LLVM generated native code object file. - pub obj_file: Option, +pub trait LLVMCallbacks: std::any::Any + 'static { + fn preopt_ir_callback(&mut self, module: &InkwellModule); + fn postopt_ir_callback(&mut self, module: &InkwellModule); + fn obj_memory_buffer_callback(&mut self, memory_buffer: &InkwellMemoryBuffer); } -pub static mut GLOBAL_OPTIONS: LLVMOptions = LLVMOptions { - pre_opt_ir: None, - post_opt_ir: None, - obj_file: None, -}; +pub struct LLVMBackendConfig { + pub callbacks: Option>>, +} diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs index febfdda0e98..f41d2b30048 100644 --- a/lib/runtime-core/src/backend.rs +++ b/lib/runtime-core/src/backend.rs @@ -200,6 +200,19 @@ pub struct Features { pub threads: bool, } +/// Use this to point to a compiler config struct provided by the backend. +/// The backend struct must support runtime reflection with `Any`, which is any +/// struct that does not contain a non-`'static` reference. +#[derive(Debug)] +pub struct BackendCompilerConfig(pub Box); + +impl BackendCompilerConfig { + /// Obtain the backend-specific compiler config struct. + pub fn get_specific(&self) -> Option<&T> { + self.0.downcast_ref::() + } +} + /// Configuration data for the compiler #[derive(Debug, Default)] pub struct CompilerConfig { @@ -210,10 +223,12 @@ pub struct CompilerConfig { pub track_state: bool, pub features: Features, - // target info used by LLVM + // Target info. Presently only supported by LLVM. pub triple: Option, pub cpu_name: Option, pub cpu_features: Option, + + pub backend_specific_config: Option, } pub trait Compiler { diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 457b6f51060..b3d82cd44be 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -9,6 +9,7 @@ )] extern crate structopt; +use std::collections::HashMap; use std::env; use std::fs::{metadata, read_to_string, File}; use std::io; @@ -17,14 +18,15 @@ use std::path::PathBuf; use std::process::exit; use std::str::FromStr; -use std::collections::HashMap; use structopt::{clap, StructOpt}; use wasmer::*; #[cfg(feature = "backend-cranelift")] use wasmer_clif_backend::CraneliftCompiler; #[cfg(feature = "backend-llvm")] -use wasmer_llvm_backend::{LLVMCompiler, LLVMOptions}; +use wasmer_llvm_backend::{ + InkwellMemoryBuffer, InkwellModule, LLVMBackendConfig, LLVMCallbacks, LLVMCompiler, +}; use wasmer_runtime::{ cache::{Cache as BaseCache, FileSystemCache, WasmHash}, Value, VERSION, @@ -40,6 +42,11 @@ use wasmer_runtime_core::{ #[cfg(feature = "wasi")] use wasmer_wasi; +#[cfg(feature = "backend-llvm")] +use std::{cell::RefCell, io::Write, rc::Rc}; +#[cfg(feature = "backend-llvm")] +use wasmer_runtime_core::backend::BackendCompilerConfig; + #[derive(Debug, StructOpt)] #[structopt(name = "wasmer", about = "Wasm execution runtime.", author)] /// The options for the wasmer Command Line Interface @@ -486,6 +493,32 @@ fn execute_wasi( Ok(()) } +#[cfg(feature = "backend-llvm")] +impl LLVMCallbacks for LLVMCLIOptions { + fn preopt_ir_callback(&mut self, module: &InkwellModule) { + if let Some(filename) = &self.pre_opt_ir { + module.print_to_file(filename).unwrap(); + } + } + + fn postopt_ir_callback(&mut self, module: &InkwellModule) { + if let Some(filename) = &self.post_opt_ir { + module.print_to_file(filename).unwrap(); + } + } + + fn obj_memory_buffer_callback(&mut self, memory_buffer: &InkwellMemoryBuffer) { + if let Some(filename) = &self.obj_file { + let mem_buf_slice = memory_buffer.as_slice(); + let mut file = File::create(filename).unwrap(); + let mut pos = 0; + while pos < mem_buf_slice.len() { + pos += file.write(&mem_buf_slice[pos..]).unwrap(); + } + } + } +} + /// Execute a wasm/wat file fn execute_wasm(options: &Run) -> Result<(), String> { let disable_cache = options.disable_cache; @@ -558,22 +591,17 @@ fn execute_wasm(options: &Run) -> Result<(), String> { .map_err(|e| format!("Can't convert from wast to wasm: {:?}", e))?; } - let compiler: Box = match get_compiler_by_backend(options.backend, options) { - Some(x) => x, - None => return Err("the requested backend is not enabled".into()), - }; + let compiler: Box = get_compiler_by_backend(options.backend, options) + .ok_or_else(|| "the requested backend is not enabled")?; + #[allow(unused_mut)] + let mut backend_specific_config = None; #[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, - } - } + backend_specific_config = Some(BackendCompilerConfig(Box::new(LLVMBackendConfig { + callbacks: Some(Rc::new(RefCell::new(options.backend_llvm_options.clone()))), + }))) } } @@ -598,6 +626,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { enforce_stack_check: true, track_state, features: options.features.into_backend_features(), + backend_specific_config, ..Default::default() }, &*compiler, @@ -610,6 +639,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { symbol_map: em_symbol_map.clone(), track_state, features: options.features.into_backend_features(), + backend_specific_config, ..Default::default() }, &*compiler, @@ -625,7 +655,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { let mut cache = unsafe { FileSystemCache::new(wasmer_cache_dir).map_err(|e| format!("Cache error: {:?}", e))? }; - let mut load_cache_key = || -> Result<_, String> { + let load_cache_key = || -> Result<_, String> { if let Some(ref prehashed_cache_key) = options.cache_key { if let Ok(module) = WasmHash::decode(prehashed_cache_key).and_then(|prehashed_key| { @@ -655,6 +685,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { symbol_map: em_symbol_map.clone(), track_state, features: options.features.into_backend_features(), + backend_specific_config, ..Default::default() }, &*compiler, From 3ba355dda431023c8a3e1a1be3bc9ab7a8ac04a7 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 5 Dec 2019 15:04:05 -0800 Subject: [PATCH 316/342] Remove deterministic flag setting default compiler; add auto logic --- Makefile | 6 ++++++ lib/runtime/src/lib.rs | 39 ++++++++++++++++----------------------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index 4acde792584..935a6a69218 100644 --- a/Makefile +++ b/Makefile @@ -192,6 +192,12 @@ check: check-bench # as default, and test a minimal set of features with only one backend # at a time. cargo check --manifest-path lib/runtime/Cargo.toml + # Check some of the cases where deterministic execution could matter + cargo check --manifest-path lib/runtime/Cargo.toml --features "deterministic-execution" + cargo check --manifest-path lib/runtime/Cargo.toml --no-default-features \ + --features=default-backend-singlepass,deterministic-execution + cargo check --manifest-path lib/runtime/Cargo.toml --no-default-features \ + --features=default-backend-llvm,deterministic-execution cargo check --release --manifest-path lib/runtime/Cargo.toml $(RUNTIME_CHECK) \ diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index 13b3dd8d4e7..58046148290 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -211,21 +211,13 @@ pub fn default_compiler() -> impl Compiler { not(feature = "docs"), any( feature = "default-backend-cranelift", - feature = "default-backend-singlepass", - feature = "deterministic-execution" + feature = "default-backend-singlepass" ) ), all( not(feature = "docs"), feature = "default-backend-cranelift", - any( - feature = "default-backend-singlepass", - feature = "deterministic-execution" - ) - ), - all( - feature = "default-backend-singlepass", - feature = "deterministic-execution" + feature = "default-backend-singlepass" ) ))] compile_error!( @@ -235,13 +227,7 @@ pub fn default_compiler() -> impl Compiler { #[cfg(all(feature = "default-backend-llvm", not(feature = "docs")))] use wasmer_llvm_backend::LLVMCompiler as DefaultCompiler; - #[cfg(all( - any( - feature = "default-backend-singlepass", - all(feature = "deterministic-execution", feature = "singlepass") - ), - not(feature = "docs") - ))] + #[cfg(all(feature = "default-backend-singlepass", not(feature = "docs")))] use wasmer_singlepass_backend::SinglePassCompiler as DefaultCompiler; #[cfg(any(feature = "default-backend-cranelift", feature = "docs"))] @@ -260,7 +246,7 @@ pub fn compiler_for_backend(backend: Backend) -> Option> { #[cfg(feature = "cranelift")] Backend::Cranelift => Some(Box::new(wasmer_clif_backend::CraneliftCompiler::new())), - #[cfg(any(feature = "singlepass", feature = "deterministic-execution"))] + #[cfg(any(feature = "singlepass"))] Backend::Singlepass => Some(Box::new( wasmer_singlepass_backend::SinglePassCompiler::new(), )), @@ -268,11 +254,18 @@ pub fn compiler_for_backend(backend: Backend) -> Option> { #[cfg(feature = "llvm")] Backend::LLVM => Some(Box::new(wasmer_llvm_backend::LLVMCompiler::new())), - #[cfg(not(all( - feature = "llvm", - any(feature = "singlepass", feature = "deterministic-execution"), - feature = "cranelift", - )))] + Backend::Auto => { + #[cfg(feature = "default-backend-singlepass")] + return Some(Box::new( + wasmer_singlepass_backend::SinglePassCompiler::new(), + )); + #[cfg(feature = "default-backend-cranelift")] + return Some(Box::new(wasmer_clif_backend::CraneliftCompiler::new())); + #[cfg(feature = "default-backend-llvm")] + return Some(Box::new(wasmer_llvm_backend::LLVMCompiler::new())); + } + + #[cfg(not(all(feature = "llvm", feature = "singlepass", feature = "cranelift")))] _ => None, } } From 27fe50ce9ec639ecd1d8698972f368494656fc5b Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Wed, 4 Dec 2019 10:38:28 -0800 Subject: [PATCH 317/342] Fix this regression test to detect the bug it was looking for in release builds too. This bug triggered an assertion failure in debug, and by examining the pre-opt IR, we can check for the bug in release mode too. --- lib/llvm-backend-tests/tests/compile.rs | 62 +++++++++++++++++++------ 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/lib/llvm-backend-tests/tests/compile.rs b/lib/llvm-backend-tests/tests/compile.rs index 17071a44a04..dc539bf2067 100644 --- a/lib/llvm-backend-tests/tests/compile.rs +++ b/lib/llvm-backend-tests/tests/compile.rs @@ -1,40 +1,72 @@ +use wasmer_llvm_backend::{InkwellMemoryBuffer, InkwellModule, LLVMBackendConfig, LLVMCallbacks}; use wasmer_llvm_backend_tests::{get_compiler, wat2wasm}; -use wasmer_runtime::imports; -use wasmer_runtime_core::compile_with; +use wasmer_runtime::{imports, CompilerConfig}; +use wasmer_runtime_core::{backend::BackendCompilerConfig, compile_with, compile_with_config}; + +use std::cell::RefCell; +use std::rc::Rc; #[test] fn crash_return_with_float_on_stack() { const MODULE: &str = r#" (module - (type (;0;) (func)) - (type (;1;) (func (param f64) (result f64))) + (type (func)) + (type (func (param f64) (result f64))) (func $_start (type 0)) (func $fmod (type 1) (param f64) (result f64) local.get 0 - f64.const 0x0p+0 (;=0;) + f64.const 0x0p+0 f64.mul - return) -) + return)) "#; 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(); } +#[derive(Debug, Default)] +pub struct RecordPreOptIR { + preopt_ir: String, +} + +impl LLVMCallbacks for RecordPreOptIR { + fn preopt_ir_callback(&mut self, module: &InkwellModule) { + self.preopt_ir = module.print_to_string().to_string(); + } + + fn postopt_ir_callback(&mut self, _: &InkwellModule) {} + + fn obj_memory_buffer_callback(&mut self, _: &InkwellMemoryBuffer) {} +} + #[test] fn crash_select_with_mismatched_pending() { - const MODULE: &str = r#" + const WAT: &str = r#" (module - (func (param f64) - f64.const 0x0p+0 (;=0;) + (func (param f64) (result f64) + f64.const 0x0p+0 local.get 0 f64.add - f64.const 0x0p+0 (;=0;) + f64.const 0x0p+0 i32.const 0 - select - drop)) + select)) "#; - let wasm_binary = wat2wasm(MODULE.as_bytes()).expect("WAST not valid or malformed"); - let module = compile_with(&wasm_binary, &get_compiler()).unwrap(); + let record_pre_opt_ir = Rc::new(RefCell::new(RecordPreOptIR::default())); + let compiler_config = CompilerConfig { + backend_specific_config: Some(BackendCompilerConfig(Box::new(LLVMBackendConfig { + callbacks: Some(record_pre_opt_ir.clone()), + }))), + ..Default::default() + }; + let wasm_binary = wat2wasm(WAT.as_bytes()).expect("WAST not valid or malformed"); + let module = compile_with_config(&wasm_binary, &get_compiler(), compiler_config).unwrap(); module.instantiate(&imports! {}).unwrap(); + const LLVM: &str = r#" + %s3 = fadd double 0.000000e+00, %s2 + %nan = fcmp uno double %s3, 0.000000e+00 + %2 = select i1 %nan, double 0x7FF8000000000000, double %s3 + %s5 = select i1 false, double %2, double 0.000000e+00 + br label %return +"#; + assert!(&record_pre_opt_ir.borrow().preopt_ir.contains(LLVM)); } From f8385e27573ecb83968a6b55585ec4cb7ea7e12c Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Fri, 6 Dec 2019 14:02:02 +0100 Subject: [PATCH 318/342] feat(bin) `wasmer` requires a strict WASI version detection. --- src/bin/wasmer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 457b6f51060..d4fee1b0dd2 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -733,7 +733,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { .map_err(|e| format!("{:?}", e))?; } else { #[cfg(feature = "wasi")] - let wasi_version = wasmer_wasi::get_wasi_version(&module); + let wasi_version = wasmer_wasi::get_wasi_version(&module, true); #[cfg(feature = "wasi")] let is_wasi = wasi_version.is_some(); #[cfg(not(feature = "wasi"))] From 8aa49f540ad4ecdd884816ffba1d888330cd6fab Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Fri, 6 Dec 2019 14:04:30 +0100 Subject: [PATCH 319/342] test(wasi) Update `get_wasi_version` signature. --- lib/wasi-tests/src/lib.rs | 2 +- lib/wasi-tests/tests/wasitests/_common.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/wasi-tests/src/lib.rs b/lib/wasi-tests/src/lib.rs index dcfa5bc8b47..6bf3626dd71 100644 --- a/lib/wasi-tests/src/lib.rs +++ b/lib/wasi-tests/src/lib.rs @@ -20,7 +20,7 @@ fn serializing_works() { .map_err(|e| format!("Can't compile module: {:?}", e)) .unwrap(); - let wasi_version = get_wasi_version(&module).expect("WASI module"); + let wasi_version = get_wasi_version(&module, true).expect("WASI module"); let import_object = generate_import_object_for_version( wasi_version, args.clone(), diff --git a/lib/wasi-tests/tests/wasitests/_common.rs b/lib/wasi-tests/tests/wasitests/_common.rs index 41bf14e44b4..04b830a91dc 100644 --- a/lib/wasi-tests/tests/wasitests/_common.rs +++ b/lib/wasi-tests/tests/wasitests/_common.rs @@ -8,7 +8,7 @@ macro_rules! assert_wasi_output { let module = wasmer_runtime::compile(&wasm_bytes[..]).expect("WASM can't be compiled"); - let wasi_version = get_wasi_version(&module).expect("WASI module"); + let wasi_version = get_wasi_version(&module, true).expect("WASI module"); let import_object = generate_import_object_for_version( wasi_version, From 45e4081e4b71573d453614b20ecda1b200d82306 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Fri, 6 Dec 2019 15:02:48 +0100 Subject: [PATCH 320/342] doc(changelog) Remove a duplication. --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 495361d2876..60ff42f8b9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,6 @@ - [#1030](https://github.com/wasmerio/wasmer/pull/1030) Ability to generate `ImportObject` for a specific version WASI version with the C API. - [#1028](https://github.com/wasmerio/wasmer/pull/1028) Introduce strict/non-strict modes for `get_wasi_version` - [#1029](https://github.com/wasmerio/wasmer/pull/1029) Add the “floating” `WasiVersion::Latest` version. -- [#1028](https://github.com/wasmerio/wasmer/pull/1028) Introduce strict/non-strict modes for `get_wasi_version` - [#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. From e32a1a637843be1be7d0693999ccf81d2ca3e074 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Fri, 6 Dec 2019 10:24:43 -0800 Subject: [PATCH 321/342] Update from feedback; add changelog entry --- CHANGELOG.md | 1 + src/bin/wasmer.rs | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 658742c4bdb..1301a1565f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## **[Unreleased]** +- [#1033](https://github.com/wasmerio/wasmer/pull/1033) Set cranelift backend as default compiler backend again, require at least one backend to be enabled for Wasmer CLI - [#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. diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 595c135022e..910b2859bfb 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -40,11 +40,11 @@ use wasmer_runtime_core::{ #[cfg(feature = "wasi")] use wasmer_wasi; -#[cfg(all( - not(feature = "backend-cranelift"), - not(feature = "backend-llvm"), - not(feature = "backend-singlepass") -))] +#[cfg(not(any( + feature = "backend-cranelift", + feature = "backend-llvm", + feature = "backend-singlepass" +)))] compile_error!("Please enable at least one of the compiler backends"); #[derive(Debug, StructOpt)] From 448faafd0dea1be47462bb75675e71b546089f5b Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Fri, 6 Dec 2019 10:28:20 -0800 Subject: [PATCH 322/342] Apply cargo fmt after GitHub merge --- src/bin/wasmer.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index d333f028e9b..9b09e679879 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -599,7 +599,12 @@ fn execute_wasm(options: &Run) -> Result<(), String> { } let compiler: Box = get_compiler_by_backend(options.backend, options) - .ok_or_else(|| format!("the requested backend, \"{}\", is not enabled", options.backend.to_string()))?; + .ok_or_else(|| { + format!( + "the requested backend, \"{}\", is not enabled", + options.backend.to_string() + ) + })?; #[allow(unused_mut)] let mut backend_specific_config = None; From d2f5690cae747afd59218ef9f482d339e4e21365 Mon Sep 17 00:00:00 2001 From: Mark McCaskey <5770194+MarkMcCaskey@users.noreply.github.com> Date: Fri, 6 Dec 2019 10:36:45 -0800 Subject: [PATCH 323/342] Improve warning message when invoking WASI functions --- src/bin/wasmer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 2cf9108d9fa..5dedb3f1138 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -478,7 +478,7 @@ fn execute_wasi( }; if let Some(invoke_fn) = options.invoke.as_ref() { - eprintln!("WARNING: Invoking a function with WASI is not officially supported in the WASI standard yet. Use this feature at your own risk, things may not work!"); + eprintln!("WARNING: Invoking aribtrary functions with WASI is not officially supported in the WASI standard yet. Use this feature at your own risk!"); let args = options.parse_args()?; let invoke_result = instance .dyn_func(invoke_fn) From 0580a117da7527fdfd68a14ede9c98e6e1228a22 Mon Sep 17 00:00:00 2001 From: Mark McCaskey <5770194+MarkMcCaskey@users.noreply.github.com> Date: Fri, 6 Dec 2019 11:54:33 -0800 Subject: [PATCH 324/342] Improve compile error message when no backends set --- src/bin/wasmer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 9b09e679879..222a58ab1c0 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -52,7 +52,7 @@ use wasmer_runtime_core::backend::BackendCompilerConfig; feature = "backend-llvm", feature = "backend-singlepass" )))] -compile_error!("Please enable at least one of the compiler backends"); +compile_error!("Please enable one or more of the compiler backends"); #[derive(Debug, StructOpt)] #[structopt(name = "wasmer", about = "Wasm execution runtime.", author)] From a221f1e5707fce40c08b09632341832483781e3a Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 6 Dec 2019 12:09:34 -0800 Subject: [PATCH 325/342] Provide a default empty implementation for the LLVMCallbacks trait. --- lib/llvm-backend-tests/tests/compile.rs | 4 ---- lib/llvm-backend/src/lib.rs | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/llvm-backend-tests/tests/compile.rs b/lib/llvm-backend-tests/tests/compile.rs index dc539bf2067..1e32f6dd08d 100644 --- a/lib/llvm-backend-tests/tests/compile.rs +++ b/lib/llvm-backend-tests/tests/compile.rs @@ -33,10 +33,6 @@ impl LLVMCallbacks for RecordPreOptIR { fn preopt_ir_callback(&mut self, module: &InkwellModule) { self.preopt_ir = module.print_to_string().to_string(); } - - fn postopt_ir_callback(&mut self, _: &InkwellModule) {} - - fn obj_memory_buffer_callback(&mut self, _: &InkwellMemoryBuffer) {} } #[test] diff --git a/lib/llvm-backend/src/lib.rs b/lib/llvm-backend/src/lib.rs index 853cfac1195..a2db088a76a 100644 --- a/lib/llvm-backend/src/lib.rs +++ b/lib/llvm-backend/src/lib.rs @@ -37,9 +37,9 @@ pub type InkwellModule<'ctx> = inkwell::module::Module<'ctx>; pub type InkwellMemoryBuffer = inkwell::memory_buffer::MemoryBuffer; pub trait LLVMCallbacks: std::any::Any + 'static { - fn preopt_ir_callback(&mut self, module: &InkwellModule); - fn postopt_ir_callback(&mut self, module: &InkwellModule); - fn obj_memory_buffer_callback(&mut self, memory_buffer: &InkwellMemoryBuffer); + fn preopt_ir_callback(&mut self, _module: &InkwellModule) {} + fn postopt_ir_callback(&mut self, _module: &InkwellModule) {} + fn obj_memory_buffer_callback(&mut self, _memory_buffer: &InkwellMemoryBuffer) {} } pub struct LLVMBackendConfig { From 87ef0d6f25696e27ee6573cc9ce55f6f7057b439 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 6 Dec 2019 22:09:04 +0000 Subject: [PATCH 326/342] Bump libc from 0.2.65 to 0.2.66 Bumps [libc](https://github.com/rust-lang/libc) from 0.2.65 to 0.2.66. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.65...0.2.66) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 86 +++++++++++++++++++++++++++--------------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eb081c3db9e..2f626498e0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -36,7 +36,7 @@ name = "atty" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -52,7 +52,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.32 (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)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -62,7 +62,7 @@ version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -243,7 +243,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -324,7 +324,7 @@ dependencies = [ "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.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)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.10 (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)", @@ -497,7 +497,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.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -507,7 +507,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.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -545,7 +545,7 @@ 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)", "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "miniz_oxide 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -628,7 +628,7 @@ 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)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -692,7 +692,7 @@ name = "hermit-abi" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -803,7 +803,7 @@ source = "git+https://github.com/TheDan64/inkwell?rev=781620e9fa30e51a6e03bd0d49 dependencies = [ "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "inkwell_internals 0.1.0 (git+https://github.com/TheDan64/inkwell?rev=781620e9fa30e51a6e03bd0d49b5f5bb7a782520)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "llvm-sys 80.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -847,7 +847,7 @@ name = "iovec" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -883,7 +883,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.65" +version = "0.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -893,7 +893,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.47 (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)", + "libc 0.2.66 (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)", ] @@ -934,7 +934,7 @@ name = "memchr" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -942,7 +942,7 @@ name = "memmap" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -985,7 +985,7 @@ dependencies = [ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1010,7 +1010,7 @@ 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)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.10.26 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1027,7 +1027,7 @@ version = "0.2.33" 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)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1039,7 +1039,7 @@ dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.47 (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)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1057,7 +1057,7 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1074,7 +1074,7 @@ dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.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)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-sys 0.9.53 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1090,7 +1090,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)", "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1109,7 +1109,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.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1148,7 +1148,7 @@ 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)", "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)", + "libc 0.2.66 (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.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1244,7 +1244,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1262,7 +1262,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" 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)", + "libc 0.2.66 (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)", @@ -1336,7 +1336,7 @@ name = "rand_jitter" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1348,7 +1348,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.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (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)", @@ -1556,7 +1556,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1741,7 +1741,7 @@ version = "3.1.0" 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)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (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)", @@ -1769,7 +1769,7 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (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)", ] @@ -2132,7 +2132,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.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (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.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2177,7 +2177,7 @@ dependencies = [ name = "wasmer-dev-utils" version = "0.11.0" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2187,7 +2187,7 @@ 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)", + "libc 0.2.66 (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.11.0", ] @@ -2210,7 +2210,7 @@ dependencies = [ name = "wasmer-kernel-loader" version = "0.1.0" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime-core 0.11.0", ] @@ -2223,7 +2223,7 @@ dependencies = [ "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "inkwell 0.1.0 (git+https://github.com/TheDan64/inkwell?rev=781620e9fa30e51a6e03bd0d49b5f5bb7a782520)", "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)", + "libc 0.2.66 (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)", @@ -2285,7 +2285,7 @@ name = "wasmer-runtime-c-api" version = "0.11.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)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime 0.11.0", "wasmer-runtime-core 0.11.0", "wasmer-wasi 0.11.0", @@ -2303,7 +2303,7 @@ dependencies = [ "hex 0.3.2 (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)", + "libc 0.2.66 (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)", @@ -2337,7 +2337,7 @@ dependencies = [ "dynasm 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "dynasmrt 0.5.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)", + "libc 0.2.66 (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.103 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2365,7 +2365,7 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "generational-arena 0.2.6 (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)", + "libc 0.2.66 (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.103 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2392,7 +2392,7 @@ name = "wasmer-win-exception-handler" version = "0.11.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)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime-core 0.11.0", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2555,7 +2555,7 @@ dependencies = [ "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.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" +"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" "checksum llvm-sys 80.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2110cd4daf9cd8e39dd3b933b1a2a2ac7315e91f7c92b3a20beab526c63b5978" "checksum lock_api 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e57b3997725d2b60dbec1297f6c2e2957cc383db1cebd6be812163f969c7d586" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" From d227f19f8df9a496f2f855cb6af770bc2aa5a984 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 6 Dec 2019 17:51:15 -0800 Subject: [PATCH 327/342] super:: in this case is just crate:: in disguise. --- 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 714fd9f5480..30e08c1a077 100644 --- a/lib/runtime/src/cache.rs +++ b/lib/runtime/src/cache.rs @@ -104,7 +104,7 @@ impl Cache for FileSystemCache { unsafe { wasmer_runtime_core::load_cache_with( serialized_cache, - super::compiler_for_backend(backend) + crate::compiler_for_backend(backend) .ok_or_else(|| CacheError::UnsupportedBackend(backend))? .as_ref(), ) From 4a27dd34a2d72c0a213ec2a5947c3583e735d3b2 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 9 Dec 2019 13:39:21 +0100 Subject: [PATCH 328/342] feat(github) Attach C & C++ headers to releases. --- azure-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2409dadda9d..6ad407923c4 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -190,6 +190,7 @@ jobs: make capi make test-capi cp target/release/libwasmer_runtime_c_api.so ./artifacts + find target/release/build -name 'wasmer.h*' -exec cp {} ./artifacts ';' displayName: Build c-api (Linux) condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) - bash: | From 03082a6960b2662ff09950a138f6c9eb7137278a Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 9 Dec 2019 13:41:35 +0100 Subject: [PATCH 329/342] doc(changelog) Add #1050. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a047d4a1f03..e013b0dc05b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## **[Unreleased]** +- [#1050](https://github.com/wasmerio/wasmer/pull/1050) Attach C & C++ headers to releases. - [#1033](https://github.com/wasmerio/wasmer/pull/1033) Set cranelift backend as default compiler backend again, require at least one backend to be enabled for Wasmer CLI - [#1030](https://github.com/wasmerio/wasmer/pull/1030) Ability to generate `ImportObject` for a specific version WASI version with the C API. - [#1028](https://github.com/wasmerio/wasmer/pull/1028) Introduce strict/non-strict modes for `get_wasi_version` From a0c628c06320582c6b84a67711ebef091bf8fab4 Mon Sep 17 00:00:00 2001 From: Patrick Ventuzelo Date: Mon, 9 Dec 2019 15:18:08 +0100 Subject: [PATCH 330/342] fix unwrap bug + replace assert, unreachable in singlepass codegen --- lib/singlepass-backend/src/codegen_x64.rs | 893 +++++++++++++++------- 1 file changed, 614 insertions(+), 279 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index eee81e3b573..e2f11ccd10d 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -944,20 +944,30 @@ impl X64FunctionCode { mut src: Location, sz_dst: Size, dst: Location, - ) { + ) -> Result<(), CodegenError> { let inner = |m: &mut Machine, a: &mut Assembler, src: Location| match dst { - Location::Imm32(_) | Location::Imm64(_) => unreachable!(), + Location::Imm32(_) | Location::Imm64(_) => { + return Err(CodegenError { + message: format!("emit_relaxed_zx_sx dst Imm: unreachable code"), + }) + } Location::Memory(_, _) => { let tmp_dst = m.acquire_temp_gpr().unwrap(); op(a, sz_src, src, sz_dst, Location::GPR(tmp_dst)); a.emit_mov(Size::S64, Location::GPR(tmp_dst), dst); m.release_temp_gpr(tmp_dst); + Ok(()) } Location::GPR(_) => { op(a, sz_src, src, sz_dst, dst); + Ok(()) + } + _ => { + return Err(CodegenError { + message: format!("emit_relaxed_zx_sx dst: unreachable code"), + }) } - _ => unreachable!(), }; match src { @@ -966,13 +976,18 @@ impl X64FunctionCode { a.emit_mov(Size::S64, src, Location::GPR(tmp_src)); src = Location::GPR(tmp_src); - inner(m, a, src); + inner(m, a, src)?; m.release_temp_gpr(tmp_src); } - Location::GPR(_) | Location::Memory(_, _) => inner(m, a, src), - _ => unreachable!(), + Location::GPR(_) | Location::Memory(_, _) => inner(m, a, src)?, + _ => { + return Err(CodegenError { + message: format!("emit_relaxed_zx_sx src: unreachable code"), + }) + } } + Ok(()) } /// Moves `src` and `dst` to valid locations for generic instructions. @@ -1055,7 +1070,7 @@ impl X64FunctionCode { src1: Location, src2: Location, dst: Location, - ) { + ) -> Result<(), CodegenError> { Self::emit_relaxed_avx_base( a, m, @@ -1063,7 +1078,8 @@ impl X64FunctionCode { src1, src2, dst, - ) + )?; + Ok(()) } /// Moves `src1` and `src2` to valid locations and possibly adds a layer of indirection for `dst` for AVX instructions. @@ -1074,7 +1090,7 @@ impl X64FunctionCode { src1: Location, src2: Location, dst: Location, - ) { + ) -> Result<(), CodegenError> { let tmp1 = m.acquire_temp_xmm().unwrap(); let tmp2 = m.acquire_temp_xmm().unwrap(); let tmp3 = m.acquire_temp_xmm().unwrap(); @@ -1096,7 +1112,11 @@ impl X64FunctionCode { a.emit_mov(Size::S64, Location::GPR(tmpg), Location::XMM(tmp1)); tmp1 } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("emit_relaxed_avx_base src1: unreachable code"), + }) + } }; let src2 = match src2 { @@ -1116,7 +1136,11 @@ impl X64FunctionCode { a.emit_mov(Size::S64, Location::GPR(tmpg), Location::XMM(tmp2)); XMMOrMemory::XMM(tmp2) } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("emit_relaxed_avx_base src2: unreachable code"), + }) + } }; match dst { @@ -1127,13 +1151,18 @@ impl X64FunctionCode { op(a, m, src1, src2, tmp3); a.emit_mov(Size::S64, Location::XMM(tmp3), dst); } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("emit_relaxed_avx_base dst: unreachable code"), + }) + } } m.release_temp_gpr(tmpg); m.release_temp_xmm(tmp3); m.release_temp_xmm(tmp2); m.release_temp_xmm(tmp1); + Ok(()) } /// I32 binary operation with both operands popped from the virtual stack. @@ -1229,7 +1258,7 @@ impl X64FunctionCode { value_stack: &mut Vec, c: Condition, loc_b: Location, - ) { + ) -> Result<(), CodegenError> { // Using Red Zone here. let loc_a = get_location_released(a, m, value_stack.pop().unwrap()); @@ -1252,9 +1281,14 @@ impl X64FunctionCode { a.emit_mov(Size::S32, Location::GPR(tmp), ret); m.release_temp_gpr(tmp); } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("emit_cmpop_i32_dynamic_b ret: unreachable code"), + }) + } } value_stack.push(ret); + Ok(()) } /// I32 comparison with both operands popped from the virtual stack. @@ -1263,9 +1297,10 @@ impl X64FunctionCode { m: &mut Machine, value_stack: &mut Vec, c: Condition, - ) { + ) -> Result<(), CodegenError> { let loc_b = get_location_released(a, m, value_stack.pop().unwrap()); - Self::emit_cmpop_i32_dynamic_b(a, m, value_stack, c, loc_b); + Self::emit_cmpop_i32_dynamic_b(a, m, value_stack, c, loc_b)?; + Ok(()) } /// I64 comparison with `loc_b` from input. @@ -1275,7 +1310,7 @@ impl X64FunctionCode { value_stack: &mut Vec, c: Condition, loc_b: Location, - ) { + ) -> Result<(), CodegenError> { // Using Red Zone here. let loc_a = get_location_released(a, m, value_stack.pop().unwrap()); @@ -1298,9 +1333,14 @@ impl X64FunctionCode { a.emit_mov(Size::S32, Location::GPR(tmp), ret); m.release_temp_gpr(tmp); } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("emit_cmpop_i64_dynamic_b ret: unreachable code"), + }) + } } value_stack.push(ret); + Ok(()) } /// I64 comparison with both operands popped from the virtual stack. @@ -1309,9 +1349,10 @@ impl X64FunctionCode { m: &mut Machine, value_stack: &mut Vec, c: Condition, - ) { + ) -> Result<(), CodegenError> { let loc_b = get_location_released(a, m, value_stack.pop().unwrap()); - Self::emit_cmpop_i64_dynamic_b(a, m, value_stack, c, loc_b); + Self::emit_cmpop_i64_dynamic_b(a, m, value_stack, c, loc_b)?; + Ok(()) } /// I32 `lzcnt`/`tzcnt`/`popcnt` with operand popped from the virtual stack. @@ -1320,7 +1361,7 @@ impl X64FunctionCode { m: &mut Machine, value_stack: &mut Vec, f: fn(&mut Assembler, Size, Location, Location), - ) { + ) -> Result<(), CodegenError> { let loc = get_location_released(a, m, value_stack.pop().unwrap()); let ret = m.acquire_locations( a, @@ -1352,9 +1393,14 @@ impl X64FunctionCode { f(a, Size::S32, loc, ret); } } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("emit_xcnt_i32 loc: unreachable code"), + }) + } } value_stack.push(ret); + Ok(()) } /// I64 `lzcnt`/`tzcnt`/`popcnt` with operand popped from the virtual stack. @@ -1363,7 +1409,7 @@ impl X64FunctionCode { m: &mut Machine, value_stack: &mut Vec, f: fn(&mut Assembler, Size, Location, Location), - ) { + ) -> Result<(), CodegenError> { let loc = get_location_released(a, m, value_stack.pop().unwrap()); let ret = m.acquire_locations( a, @@ -1395,9 +1441,14 @@ impl X64FunctionCode { f(a, Size::S64, loc, ret); } } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("emit_xcnt_i64 loc: unreachable code"), + }) + } } value_stack.push(ret); + Ok(()) } /// I32 shift with both operands popped from the virtual stack. @@ -1456,7 +1507,7 @@ impl X64FunctionCode { m: &mut Machine, value_stack: &mut Vec, f: fn(&mut Assembler, XMM, XMMOrMemory, XMM), - ) { + ) -> Result<(), CodegenError> { let loc_b = get_location_released(a, m, value_stack.pop().unwrap()); let loc_a = get_location_released(a, m, value_stack.pop().unwrap()); let ret = m.acquire_locations( @@ -1466,7 +1517,8 @@ impl X64FunctionCode { )[0]; value_stack.push(ret); - Self::emit_relaxed_avx(a, m, f, loc_a, loc_b, ret); + Self::emit_relaxed_avx(a, m, f, loc_a, loc_b, ret)?; + Ok(()) } /// Floating point (AVX) comparison with both operands popped from the virtual stack. @@ -1475,7 +1527,7 @@ impl X64FunctionCode { m: &mut Machine, value_stack: &mut Vec, f: fn(&mut Assembler, XMM, XMMOrMemory, XMM), - ) { + ) -> Result<(), CodegenError> { let loc_b = get_location_released(a, m, value_stack.pop().unwrap()); let loc_a = get_location_released(a, m, value_stack.pop().unwrap()); let ret = m.acquire_locations( @@ -1485,11 +1537,12 @@ impl X64FunctionCode { )[0]; value_stack.push(ret); - Self::emit_relaxed_avx(a, m, f, loc_a, loc_b, ret); + Self::emit_relaxed_avx(a, m, f, loc_a, loc_b, ret)?; // Workaround for behavior inconsistency among different backing implementations. // (all bits or only the least significant bit are set to one?) a.emit_and(Size::S32, Location::Imm32(1), ret); + Ok(()) } /// Floating point (AVX) binary operation with both operands popped from the virtual stack. @@ -1498,7 +1551,7 @@ impl X64FunctionCode { m: &mut Machine, value_stack: &mut Vec, f: fn(&mut Assembler, XMM, XMMOrMemory, XMM), - ) { + ) -> Result<(), CodegenError> { let loc = get_location_released(a, m, value_stack.pop().unwrap()); let ret = m.acquire_locations( a, @@ -1507,7 +1560,8 @@ impl X64FunctionCode { )[0]; value_stack.push(ret); - Self::emit_relaxed_avx(a, m, f, loc, loc, ret); + Self::emit_relaxed_avx(a, m, f, loc, loc, ret)?; + Ok(()) } /// Emits a System V call sequence. @@ -1519,7 +1573,7 @@ impl X64FunctionCode { cb: F, params: I, state_context: Option<(&mut FunctionStateMap, &mut [ControlFrame])>, - ) { + ) -> Result<(), CodegenError> { // Values pushed in this function are above the shadow region. m.state.stack_values.push(MachineValue::ExplicitShadow); @@ -1530,7 +1584,11 @@ impl X64FunctionCode { for r in used_gprs.iter() { a.emit_push(Size::S64, Location::GPR(*r)); let content = m.state.register_values[X64Register::GPR(*r).to_index().0].clone(); - assert!(content != MachineValue::Undefined); + if content == MachineValue::Undefined { + return Err(CodegenError { + message: format!("emit_call_sysv: Undefined used_gprs content"), + }); + } m.state.stack_values.push(content); } @@ -1555,7 +1613,11 @@ impl X64FunctionCode { } for r in used_xmms.iter().rev() { let content = m.state.register_values[X64Register::XMM(*r).to_index().0].clone(); - assert!(content != MachineValue::Undefined); + if content == MachineValue::Undefined { + return Err(CodegenError { + message: format!("emit_call_sysv: Undefined used_xmms content"), + }); + } m.state.stack_values.push(content); } } @@ -1610,7 +1672,9 @@ impl X64FunctionCode { } Location::Memory(reg, offset) => { if reg != GPR::RBP { - unreachable!(); + return Err(CodegenError { + message: format!("emit_call_sysv loc param: unreachable code"), + }); } m.state .stack_values @@ -1656,7 +1720,11 @@ impl X64FunctionCode { _ => a.emit_push(Size::S64, *param), } } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("emit_call_sysv loc: unreachable code"), + }) + } } } @@ -1677,7 +1745,11 @@ impl X64FunctionCode { Machine::get_param_location(0), ); // vmctx - assert!(m.state.stack_values.len() % 2 == 1); // explicit shadow takes one slot + if (m.state.stack_values.len() % 2) != 1 { + return Err(CodegenError { + message: format!("emit_call_sysv: explicit shadow takes one slot"), + }); + } cb(a); @@ -1704,7 +1776,11 @@ impl X64FunctionCode { Location::Imm32(stack_offset as u32), Location::GPR(GPR::RSP), ); - assert!(stack_offset % 8 == 0); + if (stack_offset % 8) != 0 { + return Err(CodegenError { + message: format!("emit_call_sysv: Bad restoring stack alignement"), + }); + } for _ in 0..stack_offset / 8 { m.state.stack_values.pop().unwrap(); } @@ -1737,10 +1813,12 @@ impl X64FunctionCode { m.state.stack_values.pop().unwrap(); } - assert_eq!( - m.state.stack_values.pop().unwrap(), - MachineValue::ExplicitShadow - ); + if m.state.stack_values.pop().unwrap() != MachineValue::ExplicitShadow { + return Err(CodegenError { + message: format!("emit_call_sysv: Popped value is not ExplicitShadow"), + }); + } + Ok(()) } /// Emits a System V call sequence, specialized for labels as the call target. @@ -1750,12 +1828,13 @@ impl X64FunctionCode { label: DynamicLabel, params: I, state_context: Option<(&mut FunctionStateMap, &mut [ControlFrame])>, - ) { - Self::emit_call_sysv(a, m, |a| a.emit_call_label(label), params, state_context) + ) -> Result<(), CodegenError> { + Self::emit_call_sysv(a, m, |a| a.emit_call_label(label), params, state_context)?; + Ok(()) } /// Emits a memory operation. - fn emit_memory_op( + fn emit_memory_op Result<(), CodegenError>>( module_info: &ModuleInfo, config: &CodegenConfig, a: &mut Assembler, @@ -1765,7 +1844,7 @@ impl X64FunctionCode { check_alignment: bool, value_size: usize, cb: F, - ) { + ) -> Result<(), CodegenError> { // If the memory is dynamic, we need to do bound checking at runtime. let mem_desc = match MemoryIndex::new(0).local_or_import(module_info) { LocalOrImport::Local(local_mem_index) => &module_info.memories[local_mem_index], @@ -1855,7 +1934,11 @@ impl X64FunctionCode { 1 => 2, 2 => 4, 3 => 8, - _ => unreachable!("this match is fully covered"), + _ => { + return Err(CodegenError { + message: format!("emit_memory_op align: unreachable value"), + }) + } }; if check_alignment && align != 1 { let tmp_aligncheck = m.acquire_temp_gpr().unwrap(); @@ -1873,9 +1956,10 @@ impl X64FunctionCode { m.release_temp_gpr(tmp_aligncheck); } - cb(a, m, tmp_addr); + cb(a, m, tmp_addr)?; m.release_temp_gpr(tmp_addr); + Ok(()) } /// Emits a memory operation. @@ -1892,8 +1976,12 @@ impl X64FunctionCode { memory_sz: Size, stack_sz: Size, cb: F, - ) { - assert!(memory_sz <= stack_sz); + ) -> Result<(), CodegenError> { + if memory_sz > stack_sz { + return Err(CodegenError { + message: format!("emit_compare_and_swap: memory size > stac size"), + }); + } let compare = m.reserve_unused_temp_gpr(GPR::RAX); let value = if loc == Location::GPR(GPR::R14) { @@ -1922,13 +2010,15 @@ impl X64FunctionCode { a.emit_mov(stack_sz, Location::GPR(compare), ret); cb(a, m, compare, value); a.emit_lock_cmpxchg(memory_sz, Location::GPR(value), Location::Memory(addr, 0)); + Ok(()) }, - ); + )?; a.emit_jmp(Condition::NotEqual, retry); a.emit_pop(Size::S64, Location::GPR(value)); m.release_temp_gpr(compare); + Ok(()) } // Checks for underflow/overflow/nan before IxxTrunc{U/S}F32. @@ -2149,8 +2239,11 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::GPR(GPR::RAX), ); - assert_eq!(self.machine.state.wasm_inst_offset, usize::MAX); - + if self.machine.state.wasm_inst_offset != usize::MAX { + return Err(CodegenError { + message: format!("begin_body: wasm_inst_offset not usize::MAX"), + }); + } Ok(()) } @@ -2229,7 +2322,11 @@ impl FunctionCodeGenerator for X64FunctionCode { InternalEvent::FunctionBegin(_) | InternalEvent::FunctionEnd => {} InternalEvent::GetInternal(idx) => { let idx = idx as usize; - assert!(idx < INTERNALS_SIZE); + if idx >= INTERNALS_SIZE { + return Err(CodegenError { + message: format!("GetInternal: incorrect index value"), + }); + } let tmp = self.machine.acquire_temp_gpr().unwrap(); @@ -2264,7 +2361,11 @@ impl FunctionCodeGenerator for X64FunctionCode { } InternalEvent::SetInternal(idx) => { let idx = idx as usize; - assert!(idx < INTERNALS_SIZE); + if idx >= INTERNALS_SIZE { + return Err(CodegenError { + message: format!("SetInternal: incorrect index value"), + }); + } let tmp = self.machine.acquire_temp_gpr().unwrap(); @@ -2384,7 +2485,11 @@ impl FunctionCodeGenerator for X64FunctionCode { ); } else { global_index -= module_info.imported_globals.len(); - assert!(global_index < module_info.globals.len()); + if global_index >= module_info.globals.len() { + return Err(CodegenError { + message: format!("SetGlobal: incorrect global_index value"), + }); + } a.emit_mov( Size::S64, Location::Memory( @@ -2630,20 +2735,20 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.machine, &mut self.value_stack, Condition::Equal, - ), + )?, Operator::I32Ne => Self::emit_cmpop_i32( a, &mut self.machine, &mut self.value_stack, Condition::NotEqual, - ), + )?, Operator::I32Eqz => Self::emit_cmpop_i32_dynamic_b( a, &mut self.machine, &mut self.value_stack, Condition::Equal, Location::Imm32(0), - ), + )?, Operator::I32Clz => { let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); @@ -2654,7 +2759,11 @@ impl FunctionCodeGenerator for X64FunctionCode { tmp } Location::GPR(reg) => reg, - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("I32Clz src: unreachable code"), + }) + } }; let ret = self.machine.acquire_locations( @@ -2667,7 +2776,11 @@ impl FunctionCodeGenerator for X64FunctionCode { let dst = match ret { Location::Memory(_, _) => self.machine.acquire_temp_gpr().unwrap(), Location::GPR(reg) => reg, - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("I32Clz dst: unreachable code"), + }) + } }; if a.arch_has_xzcnt() { @@ -2710,7 +2823,11 @@ impl FunctionCodeGenerator for X64FunctionCode { tmp } Location::GPR(reg) => reg, - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("I32Ctz src: unreachable code"), + }) + } }; let ret = self.machine.acquire_locations( @@ -2723,7 +2840,11 @@ impl FunctionCodeGenerator for X64FunctionCode { let dst = match ret { Location::Memory(_, _) => self.machine.acquire_temp_gpr().unwrap(), Location::GPR(reg) => reg, - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("I32Ctz dst: unreachable code"), + }) + } }; if a.arch_has_xzcnt() { @@ -2760,7 +2881,7 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.machine, &mut self.value_stack, Assembler::emit_popcnt, - ), + )?, Operator::I32Shl => Self::emit_shift_i32( a, &mut self.machine, @@ -2796,46 +2917,46 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.machine, &mut self.value_stack, Condition::Below, - ), + )?, Operator::I32LeU => Self::emit_cmpop_i32( a, &mut self.machine, &mut self.value_stack, Condition::BelowEqual, - ), + )?, Operator::I32GtU => Self::emit_cmpop_i32( a, &mut self.machine, &mut self.value_stack, Condition::Above, - ), + )?, Operator::I32GeU => Self::emit_cmpop_i32( a, &mut self.machine, &mut self.value_stack, Condition::AboveEqual, - ), + )?, Operator::I32LtS => { - Self::emit_cmpop_i32(a, &mut self.machine, &mut self.value_stack, Condition::Less) + Self::emit_cmpop_i32(a, &mut self.machine, &mut self.value_stack, Condition::Less)?; } Operator::I32LeS => Self::emit_cmpop_i32( a, &mut self.machine, &mut self.value_stack, Condition::LessEqual, - ), + )?, Operator::I32GtS => Self::emit_cmpop_i32( a, &mut self.machine, &mut self.value_stack, Condition::Greater, - ), + )?, Operator::I32GeS => Self::emit_cmpop_i32( a, &mut self.machine, &mut self.value_stack, Condition::GreaterEqual, - ), + )?, Operator::I64Const { value } => { let value = value as u64; self.value_stack.push(Location::Imm64(value)); @@ -3020,20 +3141,20 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.machine, &mut self.value_stack, Condition::Equal, - ), + )?, Operator::I64Ne => Self::emit_cmpop_i64( a, &mut self.machine, &mut self.value_stack, Condition::NotEqual, - ), + )?, Operator::I64Eqz => Self::emit_cmpop_i64_dynamic_b( a, &mut self.machine, &mut self.value_stack, Condition::Equal, Location::Imm64(0), - ), + )?, Operator::I64Clz => { let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); @@ -3044,7 +3165,11 @@ impl FunctionCodeGenerator for X64FunctionCode { tmp } Location::GPR(reg) => reg, - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("I64Clz src: unreachable code"), + }) + } }; let ret = self.machine.acquire_locations( @@ -3057,7 +3182,11 @@ impl FunctionCodeGenerator for X64FunctionCode { let dst = match ret { Location::Memory(_, _) => self.machine.acquire_temp_gpr().unwrap(), Location::GPR(reg) => reg, - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("I64Clz dst: unreachable code"), + }) + } }; if a.arch_has_xzcnt() { @@ -3100,7 +3229,11 @@ impl FunctionCodeGenerator for X64FunctionCode { tmp } Location::GPR(reg) => reg, - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("I64Ctz src: unreachable code"), + }) + } }; let ret = self.machine.acquire_locations( @@ -3113,7 +3246,11 @@ impl FunctionCodeGenerator for X64FunctionCode { let dst = match ret { Location::Memory(_, _) => self.machine.acquire_temp_gpr().unwrap(), Location::GPR(reg) => reg, - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("I64Ctz dst: unreachable code"), + }) + } }; if a.arch_has_xzcnt() { @@ -3150,7 +3287,7 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.machine, &mut self.value_stack, Assembler::emit_popcnt, - ), + )?, Operator::I64Shl => Self::emit_shift_i64( a, &mut self.machine, @@ -3186,46 +3323,46 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.machine, &mut self.value_stack, Condition::Below, - ), + )?, Operator::I64LeU => Self::emit_cmpop_i64( a, &mut self.machine, &mut self.value_stack, Condition::BelowEqual, - ), + )?, Operator::I64GtU => Self::emit_cmpop_i64( a, &mut self.machine, &mut self.value_stack, Condition::Above, - ), + )?, Operator::I64GeU => Self::emit_cmpop_i64( a, &mut self.machine, &mut self.value_stack, Condition::AboveEqual, - ), + )?, Operator::I64LtS => { - Self::emit_cmpop_i64(a, &mut self.machine, &mut self.value_stack, Condition::Less) + Self::emit_cmpop_i64(a, &mut self.machine, &mut self.value_stack, Condition::Less)?; } Operator::I64LeS => Self::emit_cmpop_i64( a, &mut self.machine, &mut self.value_stack, Condition::LessEqual, - ), + )?, Operator::I64GtS => Self::emit_cmpop_i64( a, &mut self.machine, &mut self.value_stack, Condition::Greater, - ), + )?, Operator::I64GeS => Self::emit_cmpop_i64( a, &mut self.machine, &mut self.value_stack, Condition::GreaterEqual, - ), + )?, Operator::I64ExtendUI32 => { let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); @@ -3261,7 +3398,7 @@ impl FunctionCodeGenerator for X64FunctionCode { loc, Size::S64, ret, - ); + )?; } Operator::I32Extend8S => { let loc = @@ -3281,7 +3418,7 @@ impl FunctionCodeGenerator for X64FunctionCode { loc, Size::S32, ret, - ); + )?; } Operator::I32Extend16S => { let loc = @@ -3301,7 +3438,7 @@ impl FunctionCodeGenerator for X64FunctionCode { loc, Size::S32, ret, - ); + )?; } Operator::I64Extend8S => { let loc = @@ -3321,7 +3458,7 @@ impl FunctionCodeGenerator for X64FunctionCode { loc, Size::S64, ret, - ); + )?; } Operator::I64Extend16S => { let loc = @@ -3341,7 +3478,7 @@ impl FunctionCodeGenerator for X64FunctionCode { loc, Size::S64, ret, - ); + )?; } Operator::I64Extend32S => { let loc = @@ -3361,7 +3498,7 @@ impl FunctionCodeGenerator for X64FunctionCode { loc, Size::S64, ret, - ); + )?; } Operator::I32WrapI64 => { let loc = @@ -3394,25 +3531,25 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.machine, &mut self.value_stack, Assembler::emit_vaddss, - ), + )?, Operator::F32Sub => Self::emit_fp_binop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vsubss, - ), + )?, Operator::F32Mul => Self::emit_fp_binop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vmulss, - ), + )?, Operator::F32Div => Self::emit_fp_binop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vdivss, - ), + )?, Operator::F32Max => { if !a.arch_supports_canonicalize_nan() { Self::emit_fp_binop_avx( @@ -3420,7 +3557,7 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.machine, &mut self.value_stack, Assembler::emit_vmaxss, - ); + )?; } else { let src2 = get_location_released( a, @@ -3460,7 +3597,11 @@ impl FunctionCodeGenerator for X64FunctionCode { a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp1)); tmp1 } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("F32Max src1: unreachable code"), + }) + } }; let src2 = match src2 { Location::XMM(x) => x, @@ -3478,7 +3619,11 @@ impl FunctionCodeGenerator for X64FunctionCode { a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp2)); tmp2 } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("F32Max src2: unreachable code"), + }) + } }; let tmp_xmm1 = XMM::XMM8; @@ -3515,7 +3660,11 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(_, _) | Location::GPR(_) => { a.emit_mov(Size::S64, Location::XMM(src1), ret); } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("F32Max ret: unreachable code"), + }) + } } self.machine.release_temp_gpr(tmpg2); @@ -3531,7 +3680,7 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.machine, &mut self.value_stack, Assembler::emit_vminss, - ); + )?; } else { let src2 = get_location_released( a, @@ -3571,7 +3720,11 @@ impl FunctionCodeGenerator for X64FunctionCode { a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp1)); tmp1 } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("F32Min src1: unreachable code"), + }) + } }; let src2 = match src2 { Location::XMM(x) => x, @@ -3589,7 +3742,11 @@ impl FunctionCodeGenerator for X64FunctionCode { a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp2)); tmp2 } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("F32Min src2: unreachable code"), + }) + } }; let tmp_xmm1 = XMM::XMM8; @@ -3632,7 +3789,11 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(_, _) | Location::GPR(_) => { a.emit_mov(Size::S64, Location::XMM(src1), ret); } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("F32Min ret: unreachable code"), + }) + } } self.machine.release_temp_gpr(tmpg2); @@ -3646,67 +3807,67 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpeqss, - ), + )?, Operator::F32Ne => Self::emit_fp_cmpop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpneqss, - ), + )?, Operator::F32Lt => Self::emit_fp_cmpop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpltss, - ), + )?, Operator::F32Le => Self::emit_fp_cmpop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpless, - ), + )?, Operator::F32Gt => Self::emit_fp_cmpop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpgtss, - ), + )?, Operator::F32Ge => Self::emit_fp_cmpop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpgess, - ), + )?, Operator::F32Nearest => Self::emit_fp_unop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vroundss_nearest, - ), + )?, Operator::F32Floor => Self::emit_fp_unop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vroundss_floor, - ), + )?, Operator::F32Ceil => Self::emit_fp_unop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vroundss_ceil, - ), + )?, Operator::F32Trunc => Self::emit_fp_unop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vroundss_trunc, - ), + )?, Operator::F32Sqrt => Self::emit_fp_unop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vsqrtss, - ), + )?, Operator::F32Copysign => { let loc_b = @@ -3811,25 +3972,25 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.machine, &mut self.value_stack, Assembler::emit_vaddsd, - ), + )?, Operator::F64Sub => Self::emit_fp_binop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vsubsd, - ), + )?, Operator::F64Mul => Self::emit_fp_binop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vmulsd, - ), + )?, Operator::F64Div => Self::emit_fp_binop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vdivsd, - ), + )?, Operator::F64Max => { if !a.arch_supports_canonicalize_nan() { Self::emit_fp_binop_avx( @@ -3837,7 +3998,7 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.machine, &mut self.value_stack, Assembler::emit_vmaxsd, - ); + )?; } else { let src2 = get_location_released( a, @@ -3877,7 +4038,11 @@ impl FunctionCodeGenerator for X64FunctionCode { a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp1)); tmp1 } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("F64Max src1: unreachable code"), + }) + } }; let src2 = match src2 { Location::XMM(x) => x, @@ -3895,7 +4060,11 @@ impl FunctionCodeGenerator for X64FunctionCode { a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp2)); tmp2 } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("F64Max src2: unreachable code"), + }) + } }; let tmp_xmm1 = XMM::XMM8; @@ -3932,7 +4101,11 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(_, _) | Location::GPR(_) => { a.emit_mov(Size::S64, Location::XMM(src1), ret); } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("F64Max ret: unreachable code"), + }) + } } self.machine.release_temp_gpr(tmpg2); @@ -3948,7 +4121,7 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.machine, &mut self.value_stack, Assembler::emit_vminsd, - ); + )?; } else { let src2 = get_location_released( a, @@ -3988,7 +4161,11 @@ impl FunctionCodeGenerator for X64FunctionCode { a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp1)); tmp1 } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("F64Min src1: unreachable code"), + }) + } }; let src2 = match src2 { Location::XMM(x) => x, @@ -4006,7 +4183,11 @@ impl FunctionCodeGenerator for X64FunctionCode { a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp2)); tmp2 } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("F64Min src2: unreachable code"), + }) + } }; let tmp_xmm1 = XMM::XMM8; @@ -4049,7 +4230,11 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(_, _) | Location::GPR(_) => { a.emit_mov(Size::S64, Location::XMM(src1), ret); } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("F64Min ret: unreachable code"), + }) + } } self.machine.release_temp_gpr(tmpg2); @@ -4063,67 +4248,67 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpeqsd, - ), + )?, Operator::F64Ne => Self::emit_fp_cmpop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpneqsd, - ), + )?, Operator::F64Lt => Self::emit_fp_cmpop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpltsd, - ), + )?, Operator::F64Le => Self::emit_fp_cmpop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmplesd, - ), + )?, Operator::F64Gt => Self::emit_fp_cmpop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpgtsd, - ), + )?, Operator::F64Ge => Self::emit_fp_cmpop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpgesd, - ), + )?, Operator::F64Nearest => Self::emit_fp_unop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vroundsd_nearest, - ), + )?, Operator::F64Floor => Self::emit_fp_unop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vroundsd_floor, - ), + )?, Operator::F64Ceil => Self::emit_fp_unop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vroundsd_ceil, - ), + )?, Operator::F64Trunc => Self::emit_fp_unop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vroundsd_trunc, - ), + )?, Operator::F64Sqrt => Self::emit_fp_unop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vsqrtsd, - ), + )?, Operator::F64Copysign => { let loc_b = @@ -4235,13 +4420,13 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.machine, &mut self.value_stack, Assembler::emit_vcvtss2sd, - ), + )?, Operator::F32DemoteF64 => Self::emit_fp_unop_avx( a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcvtsd2ss, - ), + )?, Operator::I32ReinterpretF32 => { let loc = @@ -5264,7 +5449,7 @@ impl FunctionCodeGenerator for X64FunctionCode { label, params.iter().map(|x| *x), Some((&mut self.fsm, &mut self.control_stack)), - ); + )?; self.machine.release_locations_only_stack(a, ¶ms); @@ -5282,7 +5467,11 @@ impl FunctionCodeGenerator for X64FunctionCode { } } Operator::CallIndirect { index, table_index } => { - assert_eq!(table_index, 0); + if table_index != 0 { + return Err(CodegenError { + message: format!("CallIndirect: table_index is not 0"), + }); + } let sig = self.signatures.get(SigIndex::new(index as usize)).unwrap(); let param_types: SmallVec<[WpType; 8]> = sig.params().iter().cloned().map(type_to_wp_type).collect(); @@ -5389,7 +5578,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, params.iter().map(|x| *x), Some((&mut self.fsm, &mut self.control_stack)), - ); + )?; self.machine.release_locations_only_stack(a, ¶ms); @@ -5422,7 +5611,7 @@ impl FunctionCodeGenerator for X64FunctionCode { WpTypeOrFuncType::Type(inner_ty) => smallvec![inner_ty], _ => { return Err(CodegenError { - message: format!("multi-value returns not yet implemented"), + message: format!("If: multi-value returns not yet implemented"), }) } }, @@ -5470,7 +5659,11 @@ impl FunctionCodeGenerator for X64FunctionCode { a.emit_label(label); frame.if_else = IfElseState::Else; } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("Else: frame.if_else unreachable code"), + }) + } } } Operator::Select => { @@ -5533,7 +5726,7 @@ impl FunctionCodeGenerator for X64FunctionCode { WpTypeOrFuncType::Type(inner_ty) => smallvec![inner_ty], _ => { return Err(CodegenError { - message: format!("multi-value returns not yet implemented"), + message: format!("Block: multi-value returns not yet implemented"), }) } }, @@ -5562,7 +5755,7 @@ impl FunctionCodeGenerator for X64FunctionCode { WpTypeOrFuncType::Type(inner_ty) => smallvec![inner_ty], _ => { return Err(CodegenError { - message: format!("multi-value returns not yet implemented"), + message: format!("Loop: multi-value returns not yet implemented"), }) } }, @@ -5629,7 +5822,7 @@ impl FunctionCodeGenerator for X64FunctionCode { }, iter::once(Location::Imm32(memory_index.index() as u32)), None, - ); + )?; let ret = self.machine.acquire_locations( a, &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], @@ -5675,7 +5868,7 @@ impl FunctionCodeGenerator for X64FunctionCode { iter::once(Location::Imm32(memory_index.index() as u32)) .chain(iter::once(param_pages)), None, - ); + )?; self.machine.release_locations_only_stack(a, &[param_pages]); @@ -5715,8 +5908,9 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), ret, ); + Ok(()) }, - ); + )?; } Operator::F32Load { ref memarg } => { let target = @@ -5746,8 +5940,9 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), ret, ); + Ok(()) }, - ); + )?; } Operator::I32Load8U { ref memarg } => { let target = @@ -5777,9 +5972,10 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), Size::S32, ret, - ); + )?; + Ok(()) }, - ); + )?; } Operator::I32Load8S { ref memarg } => { let target = @@ -5809,9 +6005,10 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), Size::S32, ret, - ); + )?; + Ok(()) }, - ); + )?; } Operator::I32Load16U { ref memarg } => { let target = @@ -5841,9 +6038,10 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), Size::S32, ret, - ); + )?; + Ok(()) }, - ); + )?; } Operator::I32Load16S { ref memarg } => { let target = @@ -5873,9 +6071,10 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), Size::S32, ret, - ); + )?; + Ok(()) }, - ); + )?; } Operator::I32Store { ref memarg } => { let target_value = @@ -5901,8 +6100,9 @@ impl FunctionCodeGenerator for X64FunctionCode { target_value, Location::Memory(addr, 0), ); + Ok(()) }, - ); + )?; } Operator::F32Store { ref memarg } => { let target_value = @@ -5928,8 +6128,9 @@ impl FunctionCodeGenerator for X64FunctionCode { target_value, Location::Memory(addr, 0), ); + Ok(()) }, - ); + )?; } Operator::I32Store8 { ref memarg } => { let target_value = @@ -5955,8 +6156,9 @@ impl FunctionCodeGenerator for X64FunctionCode { target_value, Location::Memory(addr, 0), ); + Ok(()) }, - ); + )?; } Operator::I32Store16 { ref memarg } => { let target_value = @@ -5982,8 +6184,9 @@ impl FunctionCodeGenerator for X64FunctionCode { target_value, Location::Memory(addr, 0), ); + Ok(()) }, - ); + )?; } Operator::I64Load { ref memarg } => { let target = @@ -6013,8 +6216,9 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), ret, ); + Ok(()) }, - ); + )?; } Operator::F64Load { ref memarg } => { let target = @@ -6044,8 +6248,9 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), ret, ); + Ok(()) }, - ); + )?; } Operator::I64Load8U { ref memarg } => { let target = @@ -6075,9 +6280,10 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), Size::S64, ret, - ); + )?; + Ok(()) }, - ); + )?; } Operator::I64Load8S { ref memarg } => { let target = @@ -6107,9 +6313,10 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), Size::S64, ret, - ); + )?; + Ok(()) }, - ); + )?; } Operator::I64Load16U { ref memarg } => { let target = @@ -6139,9 +6346,10 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), Size::S64, ret, - ); + )?; + Ok(()) }, - ); + )?; } Operator::I64Load16S { ref memarg } => { let target = @@ -6171,9 +6379,10 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), Size::S64, ret, - ); + )?; + Ok(()) }, - ); + )?; } Operator::I64Load32U { ref memarg } => { let target = @@ -6204,7 +6413,11 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(base, offset + 4), ); // clear upper bits } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("I64Load32U ret: unreachable code"), + }) + } } Self::emit_relaxed_binop( a, @@ -6214,8 +6427,9 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), ret, ); + Ok(()) }, - ); + )?; } Operator::I64Load32S { ref memarg } => { let target = @@ -6245,9 +6459,10 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), Size::S64, ret, - ); + )?; + Ok(()) }, - ); + )?; } Operator::I64Store { ref memarg } => { let target_value = @@ -6273,8 +6488,9 @@ impl FunctionCodeGenerator for X64FunctionCode { target_value, Location::Memory(addr, 0), ); + Ok(()) }, - ); + )?; } Operator::F64Store { ref memarg } => { let target_value = @@ -6300,8 +6516,9 @@ impl FunctionCodeGenerator for X64FunctionCode { target_value, Location::Memory(addr, 0), ); + Ok(()) }, - ); + )?; } Operator::I64Store8 { ref memarg } => { let target_value = @@ -6327,8 +6544,9 @@ impl FunctionCodeGenerator for X64FunctionCode { target_value, Location::Memory(addr, 0), ); + Ok(()) }, - ); + )?; } Operator::I64Store16 { ref memarg } => { let target_value = @@ -6354,8 +6572,9 @@ impl FunctionCodeGenerator for X64FunctionCode { target_value, Location::Memory(addr, 0), ); + Ok(()) }, - ); + )?; } Operator::I64Store32 { ref memarg } => { let target_value = @@ -6381,8 +6600,9 @@ impl FunctionCodeGenerator for X64FunctionCode { target_value, Location::Memory(addr, 0), ); + Ok(()) }, - ); + )?; } Operator::Unreachable => { Self::mark_trappable(a, &self.machine, &mut self.fsm, &mut self.control_stack); @@ -6392,7 +6612,11 @@ impl FunctionCodeGenerator for X64FunctionCode { Operator::Return => { let frame = &self.control_stack[0]; if frame.returns.len() > 0 { - assert_eq!(frame.returns.len(), 1); + if frame.returns.len() != 1 { + return Err(CodegenError { + message: format!("Return: incorrect frame.returns"), + }); + } let loc = *self.value_stack.last().unwrap(); Self::emit_relaxed_binop( a, @@ -6412,7 +6636,11 @@ impl FunctionCodeGenerator for X64FunctionCode { let frame = &self.control_stack[self.control_stack.len() - 1 - (relative_depth as usize)]; if !frame.loop_like && frame.returns.len() > 0 { - assert_eq!(frame.returns.len(), 1); + if frame.returns.len() != 1 { + return Err(CodegenError { + message: format!("Br: incorrect frame.returns"), + }); + } let loc = *self.value_stack.last().unwrap(); a.emit_mov(Size::S64, loc, Location::GPR(GPR::RAX)); } @@ -6438,7 +6666,11 @@ impl FunctionCodeGenerator for X64FunctionCode { let frame = &self.control_stack[self.control_stack.len() - 1 - (relative_depth as usize)]; if !frame.loop_like && frame.returns.len() > 0 { - assert_eq!(frame.returns.len(), 1); + if frame.returns.len() != 1 { + return Err(CodegenError { + message: format!("BrIf: incorrect frame.returns"), + }); + } let loc = *self.value_stack.last().unwrap(); a.emit_mov(Size::S64, loc, Location::GPR(GPR::RAX)); } @@ -6449,7 +6681,9 @@ impl FunctionCodeGenerator for X64FunctionCode { a.emit_label(after); } Operator::BrTable { ref table } => { - let (targets, default_target) = table.read_table().unwrap(); + let (targets, default_target) = table.read_table().map_err(|e| CodegenError { + message: format!("BrTable read_table: {:?}", e), + })?; let cond = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let table_label = a.get_label(); @@ -6480,7 +6714,14 @@ impl FunctionCodeGenerator for X64FunctionCode { let frame = &self.control_stack[self.control_stack.len() - 1 - (*target as usize)]; if !frame.loop_like && frame.returns.len() > 0 { - assert_eq!(frame.returns.len(), 1); + if frame.returns.len() != 1 { + return Err(CodegenError { + message: format!( + "BrTable: incorrect frame.returns for {:?}", + target + ), + }); + } let loc = *self.value_stack.last().unwrap(); a.emit_mov(Size::S64, loc, Location::GPR(GPR::RAX)); } @@ -6494,7 +6735,11 @@ impl FunctionCodeGenerator for X64FunctionCode { let frame = &self.control_stack [self.control_stack.len() - 1 - (default_target as usize)]; if !frame.loop_like && frame.returns.len() > 0 { - assert_eq!(frame.returns.len(), 1); + if frame.returns.len() != 1 { + return Err(CodegenError { + message: format!("BrTable: incorrect frame.returns"), + }); + } let loc = *self.value_stack.last().unwrap(); a.emit_mov(Size::S64, loc, Location::GPR(GPR::RAX)); } @@ -6547,7 +6792,11 @@ impl FunctionCodeGenerator for X64FunctionCode { } if frame.returns.len() > 0 { - assert_eq!(frame.returns.len(), 1); + if frame.returns.len() != 1 { + return Err(CodegenError { + message: format!("End: incorrect frame.returns"), + }); + } let loc = self.machine.acquire_locations( a, &[( @@ -6598,8 +6847,9 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), ret, ); + Ok(()) }, - ); + )?; } Operator::I32AtomicLoad8U { ref memarg } => { let target = @@ -6629,9 +6879,10 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), Size::S32, ret, - ); + )?; + Ok(()) }, - ); + )?; } Operator::I32AtomicLoad16U { ref memarg } => { let target = @@ -6661,9 +6912,10 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), Size::S32, ret, - ); + )?; + Ok(()) }, - ); + )?; } Operator::I32AtomicStore { ref memarg } => { let target_value = @@ -6689,8 +6941,9 @@ impl FunctionCodeGenerator for X64FunctionCode { target_value, Location::Memory(addr, 0), ); + Ok(()) }, - ); + )?; } Operator::I32AtomicStore8 { ref memarg } => { let target_value = @@ -6716,8 +6969,9 @@ impl FunctionCodeGenerator for X64FunctionCode { target_value, Location::Memory(addr, 0), ); + Ok(()) }, - ); + )?; } Operator::I32AtomicStore16 { ref memarg } => { let target_value = @@ -6743,8 +6997,9 @@ impl FunctionCodeGenerator for X64FunctionCode { target_value, Location::Memory(addr, 0), ); + Ok(()) }, - ); + )?; } Operator::I64AtomicLoad { ref memarg } => { let target = @@ -6774,8 +7029,9 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), ret, ); + Ok(()) }, - ); + )?; } Operator::I64AtomicLoad8U { ref memarg } => { let target = @@ -6805,9 +7061,10 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), Size::S64, ret, - ); + )?; + Ok(()) }, - ); + )?; } Operator::I64AtomicLoad16U { ref memarg } => { let target = @@ -6837,9 +7094,10 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), Size::S64, ret, - ); + )?; + Ok(()) }, - ); + )?; } Operator::I64AtomicLoad32U { ref memarg } => { let target = @@ -6870,7 +7128,11 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(base, offset + 4), ); // clear upper bits } - _ => unreachable!(), + _ => { + return Err(CodegenError { + message: format!("I64AtomicLoad32U ret: unreachable code"), + }) + } } Self::emit_relaxed_binop( a, @@ -6880,8 +7142,9 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), ret, ); + Ok(()) }, - ); + )?; } Operator::I64AtomicStore { ref memarg } => { let target_value = @@ -6907,8 +7170,9 @@ impl FunctionCodeGenerator for X64FunctionCode { target_value, Location::Memory(addr, 0), ); + Ok(()) }, - ); + )?; } Operator::I64AtomicStore8 { ref memarg } => { let target_value = @@ -6934,8 +7198,9 @@ impl FunctionCodeGenerator for X64FunctionCode { target_value, Location::Memory(addr, 0), ); + Ok(()) }, - ); + )?; } Operator::I64AtomicStore16 { ref memarg } => { let target_value = @@ -6961,8 +7226,9 @@ impl FunctionCodeGenerator for X64FunctionCode { target_value, Location::Memory(addr, 0), ); + Ok(()) }, - ); + )?; } Operator::I64AtomicStore32 { ref memarg } => { let target_value = @@ -6988,8 +7254,9 @@ impl FunctionCodeGenerator for X64FunctionCode { target_value, Location::Memory(addr, 0), ); + Ok(()) }, - ); + )?; } Operator::I32AtomicRmwAdd { ref memarg } => { let loc = @@ -7015,9 +7282,14 @@ impl FunctionCodeGenerator for X64FunctionCode { true, 4, |a, _m, addr| { - a.emit_lock_xadd(Size::S32, Location::GPR(value), Location::Memory(addr, 0)) + a.emit_lock_xadd( + Size::S32, + Location::GPR(value), + Location::Memory(addr, 0), + ); + Ok(()) }, - ); + )?; a.emit_mov(Size::S32, Location::GPR(value), ret); self.machine.release_temp_gpr(value); } @@ -7045,9 +7317,14 @@ impl FunctionCodeGenerator for X64FunctionCode { true, 8, |a, _m, addr| { - a.emit_lock_xadd(Size::S64, Location::GPR(value), Location::Memory(addr, 0)) + a.emit_lock_xadd( + Size::S64, + Location::GPR(value), + Location::Memory(addr, 0), + ); + Ok(()) }, - ); + )?; a.emit_mov(Size::S64, Location::GPR(value), ret); self.machine.release_temp_gpr(value); } @@ -7075,9 +7352,10 @@ impl FunctionCodeGenerator for X64FunctionCode { true, 1, |a, _m, addr| { - a.emit_lock_xadd(Size::S8, Location::GPR(value), Location::Memory(addr, 0)) + a.emit_lock_xadd(Size::S8, Location::GPR(value), Location::Memory(addr, 0)); + Ok(()) }, - ); + )?; a.emit_mov(Size::S32, Location::GPR(value), ret); self.machine.release_temp_gpr(value); } @@ -7105,9 +7383,14 @@ impl FunctionCodeGenerator for X64FunctionCode { true, 2, |a, _m, addr| { - a.emit_lock_xadd(Size::S16, Location::GPR(value), Location::Memory(addr, 0)) + a.emit_lock_xadd( + Size::S16, + Location::GPR(value), + Location::Memory(addr, 0), + ); + Ok(()) }, - ); + )?; a.emit_mov(Size::S32, Location::GPR(value), ret); self.machine.release_temp_gpr(value); } @@ -7135,9 +7418,10 @@ impl FunctionCodeGenerator for X64FunctionCode { true, 1, |a, _m, addr| { - a.emit_lock_xadd(Size::S8, Location::GPR(value), Location::Memory(addr, 0)) + a.emit_lock_xadd(Size::S8, Location::GPR(value), Location::Memory(addr, 0)); + Ok(()) }, - ); + )?; a.emit_mov(Size::S64, Location::GPR(value), ret); self.machine.release_temp_gpr(value); } @@ -7165,9 +7449,14 @@ impl FunctionCodeGenerator for X64FunctionCode { true, 2, |a, _m, addr| { - a.emit_lock_xadd(Size::S16, Location::GPR(value), Location::Memory(addr, 0)) + a.emit_lock_xadd( + Size::S16, + Location::GPR(value), + Location::Memory(addr, 0), + ); + Ok(()) }, - ); + )?; a.emit_mov(Size::S64, Location::GPR(value), ret); self.machine.release_temp_gpr(value); } @@ -7195,9 +7484,14 @@ impl FunctionCodeGenerator for X64FunctionCode { true, 4, |a, _m, addr| { - a.emit_lock_xadd(Size::S32, Location::GPR(value), Location::Memory(addr, 0)) + a.emit_lock_xadd( + Size::S32, + Location::GPR(value), + Location::Memory(addr, 0), + ); + Ok(()) }, - ); + )?; a.emit_mov(Size::S64, Location::GPR(value), ret); self.machine.release_temp_gpr(value); } @@ -7226,9 +7520,14 @@ impl FunctionCodeGenerator for X64FunctionCode { true, 4, |a, _m, addr| { - a.emit_lock_xadd(Size::S32, Location::GPR(value), Location::Memory(addr, 0)) + a.emit_lock_xadd( + Size::S32, + Location::GPR(value), + Location::Memory(addr, 0), + ); + Ok(()) }, - ); + )?; a.emit_mov(Size::S32, Location::GPR(value), ret); self.machine.release_temp_gpr(value); } @@ -7257,9 +7556,14 @@ impl FunctionCodeGenerator for X64FunctionCode { true, 8, |a, _m, addr| { - a.emit_lock_xadd(Size::S64, Location::GPR(value), Location::Memory(addr, 0)) + a.emit_lock_xadd( + Size::S64, + Location::GPR(value), + Location::Memory(addr, 0), + ); + Ok(()) }, - ); + )?; a.emit_mov(Size::S64, Location::GPR(value), ret); self.machine.release_temp_gpr(value); } @@ -7288,9 +7592,10 @@ impl FunctionCodeGenerator for X64FunctionCode { true, 1, |a, _m, addr| { - a.emit_lock_xadd(Size::S8, Location::GPR(value), Location::Memory(addr, 0)) + a.emit_lock_xadd(Size::S8, Location::GPR(value), Location::Memory(addr, 0)); + Ok(()) }, - ); + )?; a.emit_mov(Size::S32, Location::GPR(value), ret); self.machine.release_temp_gpr(value); } @@ -7319,9 +7624,14 @@ impl FunctionCodeGenerator for X64FunctionCode { true, 2, |a, _m, addr| { - a.emit_lock_xadd(Size::S16, Location::GPR(value), Location::Memory(addr, 0)) + a.emit_lock_xadd( + Size::S16, + Location::GPR(value), + Location::Memory(addr, 0), + ); + Ok(()) }, - ); + )?; a.emit_mov(Size::S32, Location::GPR(value), ret); self.machine.release_temp_gpr(value); } @@ -7350,9 +7660,10 @@ impl FunctionCodeGenerator for X64FunctionCode { true, 1, |a, _m, addr| { - a.emit_lock_xadd(Size::S8, Location::GPR(value), Location::Memory(addr, 0)) + a.emit_lock_xadd(Size::S8, Location::GPR(value), Location::Memory(addr, 0)); + Ok(()) }, - ); + )?; a.emit_mov(Size::S64, Location::GPR(value), ret); self.machine.release_temp_gpr(value); } @@ -7381,9 +7692,14 @@ impl FunctionCodeGenerator for X64FunctionCode { true, 2, |a, _m, addr| { - a.emit_lock_xadd(Size::S16, Location::GPR(value), Location::Memory(addr, 0)) + a.emit_lock_xadd( + Size::S16, + Location::GPR(value), + Location::Memory(addr, 0), + ); + Ok(()) }, - ); + )?; a.emit_mov(Size::S64, Location::GPR(value), ret); self.machine.release_temp_gpr(value); } @@ -7412,9 +7728,14 @@ impl FunctionCodeGenerator for X64FunctionCode { true, 2, |a, _m, addr| { - a.emit_lock_xadd(Size::S32, Location::GPR(value), Location::Memory(addr, 0)) + a.emit_lock_xadd( + Size::S32, + Location::GPR(value), + Location::Memory(addr, 0), + ); + Ok(()) }, - ); + )?; a.emit_mov(Size::S64, Location::GPR(value), ret); self.machine.release_temp_gpr(value); } @@ -7445,7 +7766,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a, _m, src, dst| { a.emit_and(Size::S32, Location::GPR(src), Location::GPR(dst)); }, - ); + )?; } Operator::I64AtomicRmwAnd { ref memarg } => { let loc = @@ -7474,7 +7795,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a, _m, src, dst| { a.emit_and(Size::S64, Location::GPR(src), Location::GPR(dst)); }, - ); + )?; } Operator::I32AtomicRmw8UAnd { ref memarg } => { let loc = @@ -7503,7 +7824,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a, _m, src, dst| { a.emit_and(Size::S32, Location::GPR(src), Location::GPR(dst)); }, - ); + )?; } Operator::I32AtomicRmw16UAnd { ref memarg } => { let loc = @@ -7532,7 +7853,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a, _m, src, dst| { a.emit_and(Size::S32, Location::GPR(src), Location::GPR(dst)); }, - ); + )?; } Operator::I64AtomicRmw8UAnd { ref memarg } => { let loc = @@ -7561,7 +7882,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a, _m, src, dst| { a.emit_and(Size::S64, Location::GPR(src), Location::GPR(dst)); }, - ); + )?; } Operator::I64AtomicRmw16UAnd { ref memarg } => { let loc = @@ -7590,7 +7911,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a, _m, src, dst| { a.emit_and(Size::S64, Location::GPR(src), Location::GPR(dst)); }, - ); + )?; } Operator::I64AtomicRmw32UAnd { ref memarg } => { let loc = @@ -7619,7 +7940,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a, _m, src, dst| { a.emit_and(Size::S64, Location::GPR(src), Location::GPR(dst)); }, - ); + )?; } Operator::I32AtomicRmwOr { ref memarg } => { let loc = @@ -7648,7 +7969,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a, _m, src, dst| { a.emit_or(Size::S32, Location::GPR(src), Location::GPR(dst)); }, - ); + )?; } Operator::I64AtomicRmwOr { ref memarg } => { let loc = @@ -7677,7 +7998,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a, _m, src, dst| { a.emit_or(Size::S64, Location::GPR(src), Location::GPR(dst)); }, - ); + )?; } Operator::I32AtomicRmw8UOr { ref memarg } => { let loc = @@ -7706,7 +8027,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a, _m, src, dst| { a.emit_or(Size::S32, Location::GPR(src), Location::GPR(dst)); }, - ); + )?; } Operator::I32AtomicRmw16UOr { ref memarg } => { let loc = @@ -7735,7 +8056,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a, _m, src, dst| { a.emit_or(Size::S32, Location::GPR(src), Location::GPR(dst)); }, - ); + )?; } Operator::I64AtomicRmw8UOr { ref memarg } => { let loc = @@ -7764,7 +8085,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a, _m, src, dst| { a.emit_or(Size::S64, Location::GPR(src), Location::GPR(dst)); }, - ); + )?; } Operator::I64AtomicRmw16UOr { ref memarg } => { let loc = @@ -7793,7 +8114,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a, _m, src, dst| { a.emit_or(Size::S64, Location::GPR(src), Location::GPR(dst)); }, - ); + )?; } Operator::I64AtomicRmw32UOr { ref memarg } => { let loc = @@ -7822,7 +8143,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a, _m, src, dst| { a.emit_or(Size::S64, Location::GPR(src), Location::GPR(dst)); }, - ); + )?; } Operator::I32AtomicRmwXor { ref memarg } => { let loc = @@ -7851,7 +8172,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a, _m, src, dst| { a.emit_xor(Size::S32, Location::GPR(src), Location::GPR(dst)); }, - ); + )?; } Operator::I64AtomicRmwXor { ref memarg } => { let loc = @@ -7880,7 +8201,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a, _m, src, dst| { a.emit_xor(Size::S64, Location::GPR(src), Location::GPR(dst)); }, - ); + )?; } Operator::I32AtomicRmw8UXor { ref memarg } => { let loc = @@ -7909,7 +8230,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a, _m, src, dst| { a.emit_xor(Size::S32, Location::GPR(src), Location::GPR(dst)); }, - ); + )?; } Operator::I32AtomicRmw16UXor { ref memarg } => { let loc = @@ -7938,7 +8259,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a, _m, src, dst| { a.emit_xor(Size::S32, Location::GPR(src), Location::GPR(dst)); }, - ); + )?; } Operator::I64AtomicRmw8UXor { ref memarg } => { let loc = @@ -7967,7 +8288,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a, _m, src, dst| { a.emit_xor(Size::S64, Location::GPR(src), Location::GPR(dst)); }, - ); + )?; } Operator::I64AtomicRmw16UXor { ref memarg } => { let loc = @@ -7996,7 +8317,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a, _m, src, dst| { a.emit_xor(Size::S64, Location::GPR(src), Location::GPR(dst)); }, - ); + )?; } Operator::I64AtomicRmw32UXor { ref memarg } => { let loc = @@ -8025,7 +8346,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a, _m, src, dst| { a.emit_xor(Size::S64, Location::GPR(src), Location::GPR(dst)); }, - ); + )?; } Operator::I32AtomicRmwXchg { ref memarg } => { let loc = @@ -8051,9 +8372,10 @@ impl FunctionCodeGenerator for X64FunctionCode { true, 4, |a, _m, addr| { - a.emit_xchg(Size::S32, Location::GPR(value), Location::Memory(addr, 0)) + a.emit_xchg(Size::S32, Location::GPR(value), Location::Memory(addr, 0)); + Ok(()) }, - ); + )?; a.emit_mov(Size::S32, Location::GPR(value), ret); self.machine.release_temp_gpr(value); } @@ -8081,9 +8403,10 @@ impl FunctionCodeGenerator for X64FunctionCode { true, 8, |a, _m, addr| { - a.emit_xchg(Size::S64, Location::GPR(value), Location::Memory(addr, 0)) + a.emit_xchg(Size::S64, Location::GPR(value), Location::Memory(addr, 0)); + Ok(()) }, - ); + )?; a.emit_mov(Size::S64, Location::GPR(value), ret); self.machine.release_temp_gpr(value); } @@ -8111,9 +8434,10 @@ impl FunctionCodeGenerator for X64FunctionCode { true, 1, |a, _m, addr| { - a.emit_xchg(Size::S8, Location::GPR(value), Location::Memory(addr, 0)) + a.emit_xchg(Size::S8, Location::GPR(value), Location::Memory(addr, 0)); + Ok(()) }, - ); + )?; a.emit_mov(Size::S32, Location::GPR(value), ret); self.machine.release_temp_gpr(value); } @@ -8141,9 +8465,10 @@ impl FunctionCodeGenerator for X64FunctionCode { true, 2, |a, _m, addr| { - a.emit_xchg(Size::S16, Location::GPR(value), Location::Memory(addr, 0)) + a.emit_xchg(Size::S16, Location::GPR(value), Location::Memory(addr, 0)); + Ok(()) }, - ); + )?; a.emit_mov(Size::S32, Location::GPR(value), ret); self.machine.release_temp_gpr(value); } @@ -8171,9 +8496,10 @@ impl FunctionCodeGenerator for X64FunctionCode { true, 1, |a, _m, addr| { - a.emit_xchg(Size::S8, Location::GPR(value), Location::Memory(addr, 0)) + a.emit_xchg(Size::S8, Location::GPR(value), Location::Memory(addr, 0)); + Ok(()) }, - ); + )?; a.emit_mov(Size::S64, Location::GPR(value), ret); self.machine.release_temp_gpr(value); } @@ -8201,9 +8527,10 @@ impl FunctionCodeGenerator for X64FunctionCode { true, 2, |a, _m, addr| { - a.emit_xchg(Size::S16, Location::GPR(value), Location::Memory(addr, 0)) + a.emit_xchg(Size::S16, Location::GPR(value), Location::Memory(addr, 0)); + Ok(()) }, - ); + )?; a.emit_mov(Size::S64, Location::GPR(value), ret); self.machine.release_temp_gpr(value); } @@ -8231,9 +8558,10 @@ impl FunctionCodeGenerator for X64FunctionCode { true, 4, |a, _m, addr| { - a.emit_xchg(Size::S32, Location::GPR(value), Location::Memory(addr, 0)) + a.emit_xchg(Size::S32, Location::GPR(value), Location::Memory(addr, 0)); + Ok(()) }, - ); + )?; a.emit_mov(Size::S64, Location::GPR(value), ret); self.machine.release_temp_gpr(value); } @@ -8281,8 +8609,9 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), ); a.emit_mov(Size::S32, Location::GPR(compare), ret); + Ok(()) }, - ); + )?; a.emit_pop(Size::S64, Location::GPR(value)); self.machine.release_temp_gpr(compare); } @@ -8330,8 +8659,9 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), ); a.emit_mov(Size::S64, Location::GPR(compare), ret); + Ok(()) }, - ); + )?; a.emit_pop(Size::S64, Location::GPR(value)); self.machine.release_temp_gpr(compare); } @@ -8379,8 +8709,9 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), ); a.emit_movzx(Size::S8, Location::GPR(compare), Size::S32, ret); + Ok(()) }, - ); + )?; a.emit_pop(Size::S64, Location::GPR(value)); self.machine.release_temp_gpr(compare); } @@ -8428,8 +8759,9 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), ); a.emit_movzx(Size::S16, Location::GPR(compare), Size::S32, ret); + Ok(()) }, - ); + )?; a.emit_pop(Size::S64, Location::GPR(value)); self.machine.release_temp_gpr(compare); } @@ -8477,8 +8809,9 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), ); a.emit_movzx(Size::S8, Location::GPR(compare), Size::S64, ret); + Ok(()) }, - ); + )?; a.emit_pop(Size::S64, Location::GPR(value)); self.machine.release_temp_gpr(compare); } @@ -8526,8 +8859,9 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), ); a.emit_movzx(Size::S16, Location::GPR(compare), Size::S64, ret); + Ok(()) }, - ); + )?; a.emit_pop(Size::S64, Location::GPR(value)); self.machine.release_temp_gpr(compare); } @@ -8575,8 +8909,9 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Memory(addr, 0), ); a.emit_mov(Size::S32, Location::GPR(compare), ret); + Ok(()) }, - ); + )?; a.emit_pop(Size::S64, Location::GPR(value)); self.machine.release_temp_gpr(compare); } From ae568686cbe6e10402aa3eccc0a242eb8e6a0301 Mon Sep 17 00:00:00 2001 From: Patrick Ventuzelo Date: Mon, 9 Dec 2019 15:48:43 +0100 Subject: [PATCH 331/342] add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a047d4a1f03..ffcf71bb23b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## **[Unreleased]** +- [#1052](https://github.com/wasmerio/wasmer/pull/1052) Fix minor panic and improve Error handling in singlepass backend. - [#1033](https://github.com/wasmerio/wasmer/pull/1033) Set cranelift backend as default compiler backend again, require at least one backend to be enabled for Wasmer CLI - [#1030](https://github.com/wasmerio/wasmer/pull/1030) Ability to generate `ImportObject` for a specific version WASI version with the C API. - [#1028](https://github.com/wasmerio/wasmer/pull/1028) Introduce strict/non-strict modes for `get_wasi_version` From 0a278c55eec5dff6389a0e25fa7a37daef84d353 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 9 Dec 2019 18:22:30 -0800 Subject: [PATCH 332/342] For error handling and breakpoints, use Box instead of Box. --- lib/clif-backend/src/signal/mod.rs | 8 ++++---- lib/llvm-backend/src/backend.rs | 4 ++-- lib/llvm-backend/src/code.rs | 3 ++- lib/runtime-core/src/backend.rs | 2 +- lib/runtime-core/src/codegen.rs | 2 +- lib/runtime-core/src/error.rs | 2 +- lib/runtime-core/src/fault.rs | 23 +++++++++++----------- lib/runtime-core/src/state.rs | 2 +- lib/runtime-core/src/typed_func.rs | 10 +++++----- lib/runtime-core/src/vm.rs | 2 +- lib/singlepass-backend/src/codegen_x64.rs | 6 +++--- lib/singlepass-backend/src/protect_unix.rs | 6 +++--- 12 files changed, 36 insertions(+), 34 deletions(-) diff --git a/lib/clif-backend/src/signal/mod.rs b/lib/clif-backend/src/signal/mod.rs index 116da3f56ef..5526cc4e215 100644 --- a/lib/clif-backend/src/signal/mod.rs +++ b/lib/clif-backend/src/signal/mod.rs @@ -26,12 +26,12 @@ pub use self::unix::*; pub use self::windows::*; thread_local! { - pub static TRAP_EARLY_DATA: Cell>> = Cell::new(None); + pub static TRAP_EARLY_DATA: Cell>> = Cell::new(None); } pub enum CallProtError { Trap(WasmTrapInfo), - Error(Box), + Error(Box), } pub struct Caller { @@ -67,7 +67,7 @@ impl RunnableModule for Caller { args: *const u64, rets: *mut u64, trap_info: *mut WasmTrapInfo, - user_error: *mut Option>, + user_error: *mut Option>, invoke_env: Option>, ) -> bool { let handler_data = &*invoke_env.unwrap().cast().as_ptr(); @@ -108,7 +108,7 @@ impl RunnableModule for Caller { }) } - unsafe fn do_early_trap(&self, data: Box) -> ! { + unsafe fn do_early_trap(&self, data: Box) -> ! { TRAP_EARLY_DATA.with(|cell| cell.set(Some(data))); trigger_trap() } diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index 468c3fc7c72..05831733ffa 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -66,7 +66,7 @@ extern "C" { params: *const u64, results: *mut u64, trap_out: *mut WasmTrapInfo, - user_error: *mut Option>, + user_error: *mut Option>, invoke_env: Option>, ) -> bool; } @@ -427,7 +427,7 @@ impl RunnableModule for LLVMBackend { self.msm.clone() } - unsafe fn do_early_trap(&self, data: Box) -> ! { + unsafe fn do_early_trap(&self, data: Box) -> ! { throw_any(Box::leak(data)) } } diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 4365dbf3326..f2d52349296 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -856,7 +856,8 @@ pub unsafe extern "C" fn callback_trampoline( callback: *mut BreakpointHandler, ) { let callback = Box::from_raw(callback); - let result: Result<(), Box> = callback(BreakpointInfo { fault: None }); + let result: Result<(), Box> = + callback(BreakpointInfo { fault: None }); match result { Ok(()) => *b = None, Err(e) => *b = Some(e), diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs index f41d2b30048..a1647817660 100644 --- a/lib/runtime-core/src/backend.rs +++ b/lib/runtime-core/src/backend.rs @@ -271,7 +271,7 @@ pub trait RunnableModule: Send + Sync { /// signature and an invoke function that can call the trampoline. fn get_trampoline(&self, info: &ModuleInfo, sig_index: SigIndex) -> Option; - unsafe fn do_early_trap(&self, data: Box) -> !; + unsafe fn do_early_trap(&self, data: Box) -> !; /// Returns the machine code associated with this module. fn get_code(&self) -> Option<&[u8]> { diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index a3ed432e846..bf8c5868265 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -23,7 +23,7 @@ use wasmparser::{Operator, Type as WpType}; /// A type that defines a function pointer, which is called when breakpoints occur. pub type BreakpointHandler = - Box Result<(), Box> + Send + Sync + 'static>; + Box Result<(), Box> + Send + Sync + 'static>; /// Maps instruction pointers to their breakpoint handlers. pub type BreakpointMap = Arc>; diff --git a/lib/runtime-core/src/error.rs b/lib/runtime-core/src/error.rs index f2fcf7ebd32..391386e3b4f 100644 --- a/lib/runtime-core/src/error.rs +++ b/lib/runtime-core/src/error.rs @@ -187,7 +187,7 @@ pub enum RuntimeError { /// Error. Error { /// Error data. - data: Box, + data: Box, }, } diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index bc64c15fa52..89d5b800ea7 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -61,7 +61,7 @@ type SetJmpBuffer = [i32; SETJMP_BUFFER_LEN]; struct UnwindInfo { jmpbuf: SetJmpBuffer, // in breakpoints: Option, - payload: Option>, // out + payload: Option>, // out } /// A store for boundary register preservation. @@ -182,7 +182,7 @@ pub unsafe fn clear_wasm_interrupt() { pub unsafe fn catch_unsafe_unwind R>( f: F, breakpoints: Option, -) -> Result> { +) -> Result> { let unwind = UNWIND.with(|x| x.get()); let old = (*unwind).take(); *unwind = Some(UnwindInfo { @@ -205,7 +205,7 @@ pub unsafe fn catch_unsafe_unwind R>( } /// Begins an unsafe unwind. -pub unsafe fn begin_unsafe_unwind(e: Box) -> ! { +pub unsafe fn begin_unsafe_unwind(e: Box) -> ! { let unwind = UNWIND.with(|x| x.get()); let inner = (*unwind) .as_mut() @@ -283,7 +283,7 @@ extern "C" fn signal_trap_handler( static ARCH: Architecture = Architecture::Aarch64; let mut should_unwind = false; - let mut unwind_result: Box = Box::new(()); + let mut unwind_result: Box = Box::new(()); unsafe { let fault = get_fault_info(siginfo as _, ucontext); @@ -307,7 +307,7 @@ extern "C" fn signal_trap_handler( match ib.ty { InlineBreakpointType::Trace => {} InlineBreakpointType::Middleware => { - let out: Option>> = + let out: Option>> = with_breakpoint_map(|bkpt_map| { bkpt_map.and_then(|x| x.get(&ip)).map(|x| { x(BreakpointInfo { @@ -348,13 +348,14 @@ extern "C" fn signal_trap_handler( match Signal::from_c_int(signum) { Ok(SIGTRAP) => { // breakpoint - let out: Option>> = with_breakpoint_map(|bkpt_map| { - bkpt_map.and_then(|x| x.get(&(fault.ip.get()))).map(|x| { - x(BreakpointInfo { - fault: Some(&fault), + let out: Option>> = + with_breakpoint_map(|bkpt_map| { + bkpt_map.and_then(|x| x.get(&(fault.ip.get()))).map(|x| { + x(BreakpointInfo { + fault: Some(&fault), + }) }) - }) - }); + }); match out { Some(Ok(())) => { return false; diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index a5a0a003647..7465f735e84 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -652,7 +652,7 @@ pub mod x64 { image: InstanceImage, vmctx: &mut Ctx, breakpoints: Option, - ) -> Result> { + ) -> Result> { let mut stack: Vec = vec![0; 1048576 * 8 / 8]; // 8MB stack let mut stack_offset: usize = stack.len(); diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index f1e62c23815..82b49b33cc3 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -78,7 +78,7 @@ pub type Invoke = unsafe extern "C" fn( args: *const u64, rets: *mut u64, trap_info: *mut WasmTrapInfo, - user_error: *mut Option>, + user_error: *mut Option>, extra: Option>, ) -> bool; @@ -201,7 +201,7 @@ where Rets: WasmTypeList, { /// The error type for this trait. - type Error: 'static; + type Error: Send + 'static; /// Get returns or error result. fn report(self) -> Result; } @@ -219,7 +219,7 @@ where impl TrapEarly for Result where Rets: WasmTypeList, - E: 'static, + E: Send + 'static, { type Error = E; fn report(self) -> Result { @@ -507,7 +507,7 @@ macro_rules! impl_traits { Ok(Ok(returns)) => return returns.into_c_struct(), Ok(Err(err)) => { let b: Box<_> = err.into(); - b as Box + b as Box }, Err(err) => err, }; @@ -619,7 +619,7 @@ macro_rules! impl_traits { Ok(Ok(returns)) => return returns.into_c_struct(), Ok(Err(err)) => { let b: Box<_> = err.into(); - b as Box + b as Box }, Err(err) => err, }; diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index a976336a678..352836ebff2 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -1069,7 +1069,7 @@ mod vm_ctx_tests { fn get_trampoline(&self, _module: &ModuleInfo, _sig_index: SigIndex) -> Option { unimplemented!("generate_module::get_trampoline") } - unsafe fn do_early_trap(&self, _: Box) -> ! { + unsafe fn do_early_trap(&self, _: Box) -> ! { unimplemented!("generate_module::do_early_trap") } } diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index eee81e3b573..1f1d3d4862f 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -206,7 +206,7 @@ pub struct X64FunctionCode { breakpoints: Option< HashMap< AssemblyOffset, - Box Result<(), Box> + Send + Sync + 'static>, + Box Result<(), Box> + Send + Sync + 'static>, >, >, returns: SmallVec<[WpType; 1]>, @@ -359,7 +359,7 @@ impl RunnableModule for X64ExecutionContext { args: *const u64, rets: *mut u64, trap_info: *mut WasmTrapInfo, - user_error: *mut Option>, + user_error: *mut Option>, num_params_plus_one: Option>, ) -> bool { let rm: &Box = &(&*(*ctx).module).runnable_module; @@ -533,7 +533,7 @@ impl RunnableModule for X64ExecutionContext { }) } - unsafe fn do_early_trap(&self, data: Box) -> ! { + unsafe fn do_early_trap(&self, data: Box) -> ! { protect_unix::TRAP_EARLY_DATA.with(|x| x.set(Some(data))); protect_unix::trigger_trap(); } diff --git a/lib/singlepass-backend/src/protect_unix.rs b/lib/singlepass-backend/src/protect_unix.rs index 136f9bf081a..e145d367e18 100644 --- a/lib/singlepass-backend/src/protect_unix.rs +++ b/lib/singlepass-backend/src/protect_unix.rs @@ -16,7 +16,7 @@ use wasmer_runtime_core::fault::{begin_unsafe_unwind, catch_unsafe_unwind, ensur use wasmer_runtime_core::typed_func::WasmTrapInfo; thread_local! { - pub static TRAP_EARLY_DATA: Cell>> = Cell::new(None); + pub static TRAP_EARLY_DATA: Cell>> = Cell::new(None); } pub unsafe fn trigger_trap() -> ! { @@ -25,7 +25,7 @@ pub unsafe fn trigger_trap() -> ! { pub enum CallProtError { Trap(WasmTrapInfo), - Error(Box), + Error(Box), } pub fn call_protected( @@ -48,6 +48,6 @@ pub fn call_protected( } } -pub unsafe fn throw(payload: Box) -> ! { +pub unsafe fn throw(payload: Box) -> ! { begin_unsafe_unwind(payload); } From 5198c7ed502d745a65371d2474b5bd8c46f8fa58 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 10 Dec 2019 13:24:59 -0800 Subject: [PATCH 333/342] Add changelog entry. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e013b0dc05b..0d693646c03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## **[Unreleased]** +- [#1053](https://github.com/wasmerio/wasmer/pull/1053) For RuntimeError and breakpoints, use Box instead of Box. - [#1050](https://github.com/wasmerio/wasmer/pull/1050) Attach C & C++ headers to releases. - [#1033](https://github.com/wasmerio/wasmer/pull/1033) Set cranelift backend as default compiler backend again, require at least one backend to be enabled for Wasmer CLI - [#1030](https://github.com/wasmerio/wasmer/pull/1030) Ability to generate `ImportObject` for a specific version WASI version with the C API. From a52fadf54e3ecced8dd298cffbe08e6607990d07 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Tue, 10 Dec 2019 16:07:14 -0800 Subject: [PATCH 334/342] Improve wasmer invoke function --- 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 793b15db053..06d3c1cd497 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -499,7 +499,7 @@ fn execute_wasi( .map_err(|e| format!("Invoke failed: {:?}", e))? .call(&args) .map_err(|e| format!("Calling invoke fn failed: {:?}", e))?; - println!("{} returned {:?}", invoke_fn, invoke_result); + println!("{}({:?}) returned {:?}", invoke_fn, args, invoke_result); return Ok(()); } else { result = start.call(); @@ -836,7 +836,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { .map_err(|e| format!("{:?}", e))? .call(&args) .map_err(|e| format!("{:?}", e))?; - println!("main() returned: {:?}", result); + println!("{}({:?}) returned: {:?}", invoke_fn, args, result); } } From 8e4fdcf5f101482738a0639d88580cec4e4aba9c Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Tue, 10 Dec 2019 16:10:33 -0800 Subject: [PATCH 335/342] Update src/bin/wasmer.rs --- src/bin/wasmer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 06d3c1cd497..1c2d70097a3 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -836,7 +836,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { .map_err(|e| format!("{:?}", e))? .call(&args) .map_err(|e| format!("{:?}", e))?; - println!("{}({:?}) returned: {:?}", invoke_fn, args, result); + println!("{}({:?}) returned {:?}", invoke_fn, args, result); } } From 6364c56d635515fe78882e63789a6240fd5409f8 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Tue, 10 Dec 2019 16:12:56 -0800 Subject: [PATCH 336/342] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e6cc8bc9fd..fe44540cc73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## **[Unreleased]** +- [#1054](https://github.com/wasmerio/wasmer/pull/1054) Improve `--invoke` output in Wasmer CLI - [#1053](https://github.com/wasmerio/wasmer/pull/1053) For RuntimeError and breakpoints, use Box instead of Box. - [#1052](https://github.com/wasmerio/wasmer/pull/1052) Fix minor panic and improve Error handling in singlepass backend. - [#1050](https://github.com/wasmerio/wasmer/pull/1050) Attach C & C++ headers to releases. From 727ea3ba4540e0aab7cea5a8863fb96c5583a233 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 10 Dec 2019 16:13:09 -0800 Subject: [PATCH 337/342] Add ARM CI to bors's list --- bors.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bors.toml b/bors.toml index 1003d9678c1..936db84337a 100644 --- a/bors.toml +++ b/bors.toml @@ -1,5 +1,6 @@ status = [ - "wasmerio.wasmer" + "wasmerio.wasmer", + "continuous-integration/travis-ci/push" ] required_approvals = 1 timeout_sec = 7200 From 0a9c41b313ca866cc356fff01eb79719b901c1d8 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 10 Dec 2019 17:12:35 -0800 Subject: [PATCH 338/342] Integrate Ivan's arg parsing code into --invoke Co-authored-by: Ivan Enderlin --- src/bin/wasmer.rs | 22 ++++------- src/utils.rs | 99 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 15 deletions(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 793b15db053..f3e1c9170b2 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -38,6 +38,7 @@ use wasmer_runtime_core::{ backend::{Backend, Compiler, CompilerConfig, Features, MemoryBoundCheckMode}, debug, loader::{Instance as LoadedInstance, LocalLoader}, + Module, }; #[cfg(feature = "wasi")] use wasmer_wasi; @@ -246,18 +247,9 @@ struct Run { impl Run { /// Used with the `invoke` argument - fn parse_args(&self) -> Result, String> { - let mut args: Vec = Vec::new(); - for arg in self.args.iter() { - let x = arg.as_str().parse().map_err(|_| { - format!( - "Can't parse the provided argument {:?} as a integer", - arg.as_str() - ) - })?; - args.push(Value::I32(x)); - } - Ok(args) + fn parse_args(&self, module: &Module, fn_name: &str) -> Result, String> { + utils::parse_args(module, fn_name, &self.args) + .map_err(|e| format!("Invoke failed: {:?}", e)) } } @@ -493,7 +485,7 @@ fn execute_wasi( if let Some(invoke_fn) = options.invoke.as_ref() { eprintln!("WARNING: Invoking aribtrary functions with WASI is not officially supported in the WASI standard yet. Use this feature at your own risk!"); - let args = options.parse_args()?; + let args = options.parse_args(&module, invoke_fn)?; let invoke_result = instance .dyn_func(invoke_fn) .map_err(|e| format!("Invoke failed: {:?}", e))? @@ -825,12 +817,12 @@ fn execute_wasm(options: &Run) -> Result<(), String> { .instantiate(&import_object) .map_err(|e| format!("Can't instantiate module: {:?}", e))?; - let args = options.parse_args()?; - let invoke_fn = match options.invoke.as_ref() { Some(fun) => fun, _ => "main", }; + let args = options.parse_args(&module, invoke_fn)?; + let result = instance .dyn_func(&invoke_fn) .map_err(|e| format!("{:?}", e))? diff --git a/src/utils.rs b/src/utils.rs index fd96dc15bb0..2f2b0072fd7 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,6 +1,105 @@ //! Utility functions for the WebAssembly module +use wasmer_runtime::{types::Type, Module, Value}; +use wasmer_runtime_core::{backend::SigRegistry, module::ExportIndex}; + /// Detect if a provided binary is a Wasm file pub fn is_wasm_binary(binary: &[u8]) -> bool { binary.starts_with(&[b'\0', b'a', b's', b'm']) } + +#[derive(Debug, Clone, Copy)] +pub enum InvokeError { + CouldNotFindFunction, + ExportNotFunction, + WrongNumArgs { expected: u16, found: u16 }, + CouldNotParseArgs, +} + +/// Parses arguments for the `--invoke` flag on the run command +pub fn parse_args( + module: &Module, + fn_name: &str, + args: &[String], +) -> Result, InvokeError> { + let export_index = module + .info() + .exports + .get(fn_name) + .ok_or(InvokeError::CouldNotFindFunction)?; + + let signature = if let ExportIndex::Func(func_index) = export_index { + let sig_index = module + .info() + .func_assoc + .get(*func_index) + .expect("broken invariant, incorrect func index"); + SigRegistry.lookup_signature_ref(&module.info().signatures[*sig_index]) + } else { + return Err(InvokeError::ExportNotFunction); + }; + + let parameter_types = signature.params(); + + if args.len() != parameter_types.len() { + return Err(InvokeError::WrongNumArgs { + expected: parameter_types.len() as _, + found: args.len() as _, + }); + } else { + args.iter() + .enumerate() + .try_fold( + Vec::with_capacity(args.len()), + |mut accumulator, (nth, argument)| { + if let Some(value) = match parameter_types[nth] { + Type::I32 => argument + .parse::() + .map(|v| Some(Value::I32(v))) + .unwrap_or_else(|_| { + eprintln!("Failed to parse `{:?}` as an `i32`", argument); + None + }), + Type::I64 => argument + .parse::() + .map(|v| Some(Value::I64(v))) + .unwrap_or_else(|_| { + eprintln!("Failed to parse `{:?}` as an `i64`", argument); + None + }), + Type::V128 => argument + .parse::() + .map(|v| Some(Value::V128(v))) + .unwrap_or_else(|_| { + eprintln!("Failed to parse `{:?}` as an `i64`", argument); + None + }), + Type::F32 => argument + .parse::() + .map(|v| Some(Value::F32(v))) + .unwrap_or_else(|_| { + eprintln!("Failed to parse `{:?}` as an `f32`", argument); + None + }), + Type::F64 => argument + .parse::() + .map(|v| Some(Value::F64(v))) + .unwrap_or_else(|_| { + eprintln!("Failed to parse `{:?}` as an `f64`", argument); + None + }), + } { + accumulator.push(value); + + Some(accumulator) + } else { + None + } + }, + ) + .map_or_else( + || Err(InvokeError::CouldNotParseArgs), + |arguments: Vec| Ok(arguments), + ) + } +} From bc8d5a542cad36bb6464acb6abf0d0316fed3c8f Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 10 Dec 2019 17:37:22 -0800 Subject: [PATCH 339/342] Return parse error strings rather than printing them in invoke parse --- src/utils.rs | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/utils.rs b/src/utils.rs index 2f2b0072fd7..1feec86b28a 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -8,12 +8,12 @@ pub fn is_wasm_binary(binary: &[u8]) -> bool { binary.starts_with(&[b'\0', b'a', b's', b'm']) } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone)] pub enum InvokeError { CouldNotFindFunction, ExportNotFunction, WrongNumArgs { expected: u16, found: u16 }, - CouldNotParseArgs, + CouldNotParseArg(String), } /// Parses arguments for the `--invoke` flag on the run command @@ -40,6 +40,7 @@ pub fn parse_args( }; let parameter_types = signature.params(); + let mut arg_error = None; if args.len() != parameter_types.len() { return Err(InvokeError::WrongNumArgs { @@ -57,35 +58,50 @@ pub fn parse_args( .parse::() .map(|v| Some(Value::I32(v))) .unwrap_or_else(|_| { - eprintln!("Failed to parse `{:?}` as an `i32`", argument); + arg_error = Some(InvokeError::CouldNotParseArg(format!( + "Failed to parse `{:?}` as an `i32`", + argument + ))); None }), Type::I64 => argument .parse::() .map(|v| Some(Value::I64(v))) .unwrap_or_else(|_| { - eprintln!("Failed to parse `{:?}` as an `i64`", argument); + arg_error = Some(InvokeError::CouldNotParseArg(format!( + "Failed to parse `{:?}` as an `i64`", + argument + ))); None }), Type::V128 => argument .parse::() .map(|v| Some(Value::V128(v))) .unwrap_or_else(|_| { - eprintln!("Failed to parse `{:?}` as an `i64`", argument); + arg_error = Some(InvokeError::CouldNotParseArg(format!( + "Failed to parse `{:?}` as an `i128`", + argument + ))); None }), Type::F32 => argument .parse::() .map(|v| Some(Value::F32(v))) .unwrap_or_else(|_| { - eprintln!("Failed to parse `{:?}` as an `f32`", argument); + arg_error = Some(InvokeError::CouldNotParseArg(format!( + "Failed to parse `{:?}` as an `f32`", + argument + ))); None }), Type::F64 => argument .parse::() .map(|v| Some(Value::F64(v))) .unwrap_or_else(|_| { - eprintln!("Failed to parse `{:?}` as an `f64`", argument); + arg_error = Some(InvokeError::CouldNotParseArg(format!( + "Failed to parse `{:?}` as an `f64`", + argument + ))); None }), } { @@ -98,7 +114,7 @@ pub fn parse_args( }, ) .map_or_else( - || Err(InvokeError::CouldNotParseArgs), + || Err(arg_error.unwrap()), |arguments: Vec| Ok(arguments), ) } From 5aa70a8ae4409761e74cbac9900db18f519f0083 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Tue, 10 Dec 2019 17:57:26 -0800 Subject: [PATCH 340/342] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe44540cc73..29014cb9a5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## **[Unreleased]** +- [#1056](https://github.com/wasmerio/wasmer/pull/1056) Improved `--invoke` args parsing (supporting `i32`, `i64`, `f32` and `f32`) in Wasmer CLI - [#1054](https://github.com/wasmerio/wasmer/pull/1054) Improve `--invoke` output in Wasmer CLI - [#1053](https://github.com/wasmerio/wasmer/pull/1053) For RuntimeError and breakpoints, use Box instead of Box. - [#1052](https://github.com/wasmerio/wasmer/pull/1052) Fix minor panic and improve Error handling in singlepass backend. From 499a408eff6340a3f9fc427857724e0fc1d5e639 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 11 Dec 2019 02:04:08 +0000 Subject: [PATCH 341/342] Bump serde_bytes from 0.11.2 to 0.11.3 Bumps [serde_bytes](https://github.com/serde-rs/bytes) from 0.11.2 to 0.11.3. - [Release notes](https://github.com/serde-rs/bytes/releases) - [Commits](https://github.com/serde-rs/bytes/compare/0.11.2...0.11.3) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f626498e0c..c18b0e87611 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1600,7 +1600,7 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2137,7 +2137,7 @@ dependencies = [ "rayon 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.103 (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_bytes 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.103 (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)", @@ -2310,7 +2310,7 @@ dependencies = [ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.103 (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_bytes 0.11.3 (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)", "wasmparser 0.39.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2633,7 +2633,7 @@ dependencies = [ "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "1217f97ab8e8904b57dd22eb61cde455fa7446a9c1cf43966066da047c1f3702" "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_bytes 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "325a073952621257820e7a3469f55ba4726d8b28657e7e36653d1c36dc2c84ae" "checksum serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "a8c6faef9a2e64b0064f48570289b4bf8823b7581f1d6157c1b52152306651d0" "checksum serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)" = "1a3351dcbc1f067e2c92ab7c3c1f288ad1a4cffc470b5aaddb4c2e0a3ae80043" "checksum serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a" From 52cb3a18a44aca3194997552d39e2097863312fb Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 11 Dec 2019 02:04:10 +0000 Subject: [PATCH 342/342] Bump cc from 1.0.47 to 1.0.48 Bumps [cc](https://github.com/alexcrichton/cc-rs) from 1.0.47 to 1.0.48. - [Release notes](https://github.com/alexcrichton/cc-rs/releases) - [Commits](https://github.com/alexcrichton/cc-rs/compare/1.0.47...1.0.48) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f626498e0c..77fea26bff5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,7 +61,7 @@ name = "backtrace-sys" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -168,7 +168,7 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.47" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -203,7 +203,7 @@ name = "cmake" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -891,7 +891,7 @@ name = "llvm-sys" version = "80.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.48 (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.66 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1037,7 +1037,7 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.48 (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.66 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1089,7 +1089,7 @@ version = "0.9.53" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1386,7 +1386,7 @@ version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2067,7 +2067,7 @@ name = "wabt-sys" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.48 (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)", ] @@ -2219,7 +2219,7 @@ name = "wasmer-llvm-backend" version = "0.11.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.48 (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/TheDan64/inkwell?rev=781620e9fa30e51a6e03bd0d49b5f5bb7a782520)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2297,7 +2297,7 @@ version = "0.11.0" dependencies = [ "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "blake2b_simd 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.48 (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)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2477,7 +2477,7 @@ dependencies = [ "checksum cargo_toml 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e7877b00aaf997d7ed66a81281d3a8b9f9da5361df05b72785b985349979a0f3" "checksum cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" "checksum cbindgen 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9daec6140ab4dcd38c3dd57e580b59a621172a526ac79f1527af760a55afeafd" -"checksum cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "aa87058dce70a3ff5621797f1506cb837edd02ac4c0ae642b4542dce802908b8" +"checksum cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "f52a465a666ca3d838ebbf08b241383421412fe7ebb463527bba275526d89f76" "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"

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
$ynkp(p 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 diff --git a/lib/wasi-tests/wasitests/writing.wasm b/lib/wasi-tests/wasitests/writing.wasm index ce7e0180a7d23744380c7eaf2ffac6e6b0c99de6..0b8b96abcdf133b3850a1c31adea870245e2ab9e 100755 GIT binary patch delta 20852 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 delta 20981 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 diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index 5854690352d..3db7323e7c9 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -1724,12 +1724,25 @@ pub fn path_open( } } let mut open_options = std::fs::OpenOptions::new(); + let write_permission = adjusted_rights & __WASI_RIGHT_FD_WRITE != 0; + // append, truncate, and create all require the permission to write + let (append_permission, truncate_permission, create_permission) = + if write_permission { + ( + fs_flags & __WASI_FDFLAG_APPEND != 0, + o_flags & __WASI_O_TRUNC != 0, + o_flags & __WASI_O_CREAT != 0, + ) + } else { + (false, false, false) + }; let open_options = open_options .read(true) // TODO: ensure these rights are actually valid given parent, etc. - .write(adjusted_rights & __WASI_RIGHT_FD_WRITE != 0) - .create(o_flags & __WASI_O_CREAT != 0) - .truncate(o_flags & __WASI_O_TRUNC != 0); + .write(write_permission) + .create(create_permission) + .append(append_permission) + .truncate(truncate_permission); open_flags |= Fd::READ; if adjusted_rights & __WASI_RIGHT_FD_WRITE != 0 { open_flags |= Fd::WRITE; @@ -1798,6 +1811,7 @@ pub fn path_open( let mut open_options = std::fs::OpenOptions::new(); let open_options = open_options .read(true) + .append(fs_flags & __WASI_FDFLAG_APPEND != 0) // TODO: ensure these rights are actually valid given parent, etc. // write access is required for creating a file .write(true) From a94fabf56e0bff129f6776ef0bbaa1f3c76df69a Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Fri, 8 Nov 2019 11:35:59 -0800 Subject: [PATCH 085/342] Update supported Rust version to 1.38 --- CHANGELOG.md | 1 + Cargo.toml | 1 + README.md | 2 +- azure-pipelines.yml | 8 +-- lib/singlepass-backend/src/emitter_x64.rs | 88 ++++++----------------- 5 files changed, 29 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index afe906514e8..144292117fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## **[Unreleased]** +- [#940](https://github.com/wasmerio/wasmer/pull/940) Update supported Rust version to 1.38+ - [#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 diff --git a/Cargo.toml b/Cargo.toml index 2a47f943de4..0fe11919fb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ repository = "https://github.com/wasmerio/wasmer" publish = true description = "High-Performance WebAssembly JIT interpreter" license = "MIT" +default-run = "wasmer" include = [ "examples/**/*", "src/**/*", diff --git a/README.md b/README.md index 7e7f39cb154..98533edf91b 100644 --- a/README.md +++ b/README.md @@ -181,7 +181,7 @@ nginx and Lua do not work on Windows - you can track the progress on [this issue ## Building -[![Rustc Version 1.37+](https://img.shields.io/badge/rustc-1.37+-red.svg?style=flat-square)](https://blog.rust-lang.org/2019/08/15/Rust-1.37.0.html) +[![Rustc Version 1.38+](https://img.shields.io/badge/rustc-1.37+-red.svg?style=flat-square)](https://blog.rust-lang.org/2019/09/26/Rust-1.38.0.html) Wasmer is built with [Cargo](https://crates.io/), the Rust package manager. diff --git a/azure-pipelines.yml b/azure-pipelines.yml index db05b2d340d..f86ead33af9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -22,7 +22,7 @@ jobs: - script: cargo fmt --all -- --check displayName: Lint variables: - rust_toolchain: '1.37.0' + rust_toolchain: '1.38.0' - job: Test strategy: @@ -39,7 +39,7 @@ jobs: CARGO_HTTP_CHECK_REVOKE: false windows: imageName: "vs2017-win2016" - rust_toolchain: '1.37.0' + rust_toolchain: '1.38.0' pool: vmImage: $(imageName) condition: in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying') @@ -100,7 +100,7 @@ jobs: MACOSX_DEPLOYMENT_TARGET: 10.10 windows: imageName: "vs2017-win2016" - rust_toolchain: '1.37.0' + rust_toolchain: '1.38.0' # RUSTFLAGS: -Ctarget-feature=+crt-static pool: vmImage: $(imageName) @@ -163,7 +163,7 @@ jobs: MACOSX_DEPLOYMENT_TARGET: 10.10 windows: imageName: "vs2017-win2016" - rust_toolchain: '1.37.0' + rust_toolchain: '1.38.0' # RUSTFLAGS: -Ctarget-feature=+crt-static pool: vmImage: $(imageName) diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index 251868231f1..a40d5b5e5f0 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -709,18 +709,14 @@ impl Emitter for Assembler { match (sz, src) { (Size::S64, Location::Imm32(src)) => dynasm!(self ; push src as i32), (Size::S64, Location::GPR(src)) => dynasm!(self ; push Rq(src as u8)), - (Size::S64, Location::Memory(src, disp)) => { - dynasm!(self ; push QWORD [Rq(src as u8) + disp]) - } + (Size::S64, Location::Memory(src, disp)) => dynasm!(self ; push QWORD [Rq(src as u8) + disp]), _ => panic!("singlepass can't emit PUSH {:?} {:?}", sz, src), } } fn emit_pop(&mut self, sz: Size, dst: Location) { match (sz, dst) { (Size::S64, Location::GPR(dst)) => dynasm!(self ; pop Rq(dst as u8)), - (Size::S64, Location::Memory(dst, disp)) => { - dynasm!(self ; pop QWORD [Rq(dst as u8) + disp]) - } + (Size::S64, Location::Memory(dst, disp)) => dynasm!(self ; pop QWORD [Rq(dst as u8) + disp]), _ => panic!("singlepass can't emit POP {:?} {:?}", sz, dst), } } @@ -742,21 +738,13 @@ impl Emitter for Assembler { fn emit_neg(&mut self, sz: Size, value: Location) { match (sz, value) { (Size::S8, Location::GPR(value)) => dynasm!(self ; neg Rb(value as u8)), - (Size::S8, Location::Memory(value, disp)) => { - dynasm!(self ; neg [Rq(value as u8) + disp]) - } + (Size::S8, Location::Memory(value, disp)) => dynasm!(self ; neg [Rq(value as u8) + disp]), (Size::S16, Location::GPR(value)) => dynasm!(self ; neg Rw(value as u8)), - (Size::S16, Location::Memory(value, disp)) => { - dynasm!(self ; neg [Rq(value as u8) + disp]) - } + (Size::S16, Location::Memory(value, disp)) => dynasm!(self ; neg [Rq(value as u8) + disp]), (Size::S32, Location::GPR(value)) => dynasm!(self ; neg Rd(value as u8)), - (Size::S32, Location::Memory(value, disp)) => { - dynasm!(self ; neg [Rq(value as u8) + disp]) - } + (Size::S32, Location::Memory(value, disp)) => dynasm!(self ; neg [Rq(value as u8) + disp]), (Size::S64, Location::GPR(value)) => dynasm!(self ; neg Rq(value as u8)), - (Size::S64, Location::Memory(value, disp)) => { - dynasm!(self ; neg [Rq(value as u8) + disp]) - } + (Size::S64, Location::Memory(value, disp)) => dynasm!(self ; neg [Rq(value as u8) + disp]), _ => panic!("singlepass can't emit NEG {:?} {:?}", sz, value), } } @@ -1009,30 +997,18 @@ 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), }; } 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)) - } + (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), }; } @@ -1104,77 +1080,57 @@ 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)), } } 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)) - } + 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)), - XMMOrMemory::Memory(base, disp) => { - dynasm!(self ; ucomiss Rx(dst as u8), [Rq(base as u8) + disp]) - } + XMMOrMemory::Memory(base, disp) => dynasm!(self ; ucomiss Rx(dst as u8), [Rq(base as u8) + disp]), } } fn emit_ucomisd(&mut self, src: XMMOrMemory, dst: XMM) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; ucomisd Rx(dst as u8), Rx(x as u8)), - XMMOrMemory::Memory(base, disp) => { - dynasm!(self ; ucomisd Rx(dst as u8), [Rq(base as u8) + disp]) - } + XMMOrMemory::Memory(base, disp) => dynasm!(self ; ucomisd Rx(dst as u8), [Rq(base as u8) + disp]), } } fn emit_cvttss2si_32(&mut self, src: XMMOrMemory, dst: GPR) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; cvttss2si Rd(dst as u8), Rx(x as u8)), - XMMOrMemory::Memory(base, disp) => { - dynasm!(self ; cvttss2si Rd(dst as u8), [Rq(base as u8) + disp]) - } + XMMOrMemory::Memory(base, disp) => dynasm!(self ; cvttss2si Rd(dst as u8), [Rq(base as u8) + disp]), } } fn emit_cvttss2si_64(&mut self, src: XMMOrMemory, dst: GPR) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; cvttss2si Rq(dst as u8), Rx(x as u8)), - XMMOrMemory::Memory(base, disp) => { - dynasm!(self ; cvttss2si Rq(dst as u8), [Rq(base as u8) + disp]) - } + XMMOrMemory::Memory(base, disp) => dynasm!(self ; cvttss2si Rq(dst as u8), [Rq(base as u8) + disp]), } } fn emit_cvttsd2si_32(&mut self, src: XMMOrMemory, dst: GPR) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; cvttsd2si Rd(dst as u8), Rx(x as u8)), - XMMOrMemory::Memory(base, disp) => { - dynasm!(self ; cvttsd2si Rd(dst as u8), [Rq(base as u8) + disp]) - } + XMMOrMemory::Memory(base, disp) => dynasm!(self ; cvttsd2si Rd(dst as u8), [Rq(base as u8) + disp]), } } fn emit_cvttsd2si_64(&mut self, src: XMMOrMemory, dst: GPR) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; cvttsd2si Rq(dst as u8), Rx(x as u8)), - XMMOrMemory::Memory(base, disp) => { - dynasm!(self ; cvttsd2si Rq(dst as u8), [Rq(base as u8) + disp]) - } + XMMOrMemory::Memory(base, disp) => dynasm!(self ; cvttsd2si Rq(dst as u8), [Rq(base as u8) + disp]), } } From 674a70fa0509d9333939a1425df2ccddefc2b656 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 8 Nov 2019 13:13:58 -0800 Subject: [PATCH 086/342] Create function declarations before starting the body of the first function. --- lib/llvm-backend/src/code.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 7b5f2d1a233..eee995895ee 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -22,6 +22,7 @@ use inkwell::{ use smallvec::SmallVec; use std::{ cell::RefCell, + collections::HashMap, rc::Rc, sync::{Arc, RwLock}, }; @@ -851,6 +852,7 @@ pub struct LLVMModuleCodeGenerator { signatures: Map, signatures_raw: Map, function_signatures: Option>>, + llvm_functions: HashMap, func_import_count: usize, personality_func: FunctionValue, module: Rc>, @@ -8019,6 +8021,7 @@ impl ModuleCodeGenerator signatures: Map::new(), signatures_raw: Map::new(), function_signatures: None, + llvm_functions: HashMap::new(), func_import_count: 0, personality_func, stackmaps: Rc::new(RefCell::new(StackmapRegistry::default())), @@ -8053,15 +8056,11 @@ impl ModuleCodeGenerator ), }; - let sig_id = self.function_signatures.as_ref().unwrap() - [FuncIndex::new(self.func_import_count + self.functions.len())]; + let func_index = FuncIndex::new(self.func_import_count + self.functions.len()); + let sig_id = self.function_signatures.as_ref().unwrap()[func_index]; let func_sig = self.signatures_raw[sig_id].clone(); - let function = self.module.borrow_mut().add_function( - &format!("fn{}", self.func_import_count + self.functions.len()), - self.signatures[sig_id], - Some(Linkage::External), - ); + let function = &self.llvm_functions[&func_index]; function.set_personality_function(self.personality_func); let mut state = State::new(); @@ -8119,7 +8118,7 @@ impl ModuleCodeGenerator builder: Some(builder), alloca_builder: Some(alloca_builder), intrinsics: Some(intrinsics), - function, + function: *function, func_sig: func_sig, locals, signatures: self.signatures.clone(), @@ -8233,6 +8232,14 @@ impl ModuleCodeGenerator &mut self, assoc: Map, ) -> Result<(), CodegenError> { + for (index, sig_id) in &assoc { + let function = self.module.borrow_mut().add_function( + &format!("fn{}", index.index()), + self.signatures[*sig_id], + Some(Linkage::External), + ); + self.llvm_functions.insert(index, function); + } self.function_signatures = Some(Arc::new(assoc)); Ok(()) } From 2957b6abd883e3d2ae2fafeaf10700e9cbb68d89 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 8 Nov 2019 13:38:23 -0800 Subject: [PATCH 087/342] Emit direct calls for local functions, but not for imports. --- lib/llvm-backend/src/code.rs | 23 +++++------- lib/llvm-backend/src/intrinsics.rs | 56 ++---------------------------- 2 files changed, 11 insertions(+), 68 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index eee995895ee..4eae3aeb6e3 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -852,7 +852,7 @@ pub struct LLVMModuleCodeGenerator { signatures: Map, signatures_raw: Map, function_signatures: Option>>, - llvm_functions: HashMap, + llvm_functions: Rc>>, func_import_count: usize, personality_func: FunctionValue, module: Rc>, @@ -867,6 +867,7 @@ pub struct LLVMFunctionCodeGenerator { alloca_builder: Option, intrinsics: Option, state: State, + llvm_functions: Rc>>, function: FunctionValue, func_sig: FuncSig, signatures: Map, @@ -1694,7 +1695,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let func_sig = &info.signatures[sigindex]; let (params, func_ptr) = match func_index.local_or_import(info) { - LocalOrImport::Local(local_func_index) => { + LocalOrImport::Local(_) => { let params: Vec<_> = std::iter::once(ctx.basic()) .chain( state @@ -1724,15 +1725,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .collect(); - let func_ptr = ctx.local_func( - local_func_index, - llvm_sig, - intrinsics, - self.module.clone(), - builder, - ); + let func_ptr = self.llvm_functions.borrow_mut()[&func_index]; - (params, func_ptr) + (params, func_ptr.as_global_value().as_pointer_value()) } LocalOrImport::Import(import_func_index) => { let (func_ptr_untyped, ctx_ptr) = @@ -1768,7 +1763,6 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .collect(); let func_ptr_ty = llvm_sig.ptr_type(AddressSpace::Generic); - let func_ptr = builder.build_pointer_cast( func_ptr_untyped, func_ptr_ty, @@ -8021,7 +8015,7 @@ impl ModuleCodeGenerator signatures: Map::new(), signatures_raw: Map::new(), function_signatures: None, - llvm_functions: HashMap::new(), + llvm_functions: Rc::new(RefCell::new(HashMap::new())), func_import_count: 0, personality_func, stackmaps: Rc::new(RefCell::new(StackmapRegistry::default())), @@ -8060,7 +8054,7 @@ impl ModuleCodeGenerator let sig_id = self.function_signatures.as_ref().unwrap()[func_index]; let func_sig = self.signatures_raw[sig_id].clone(); - let function = &self.llvm_functions[&func_index]; + let function = &self.llvm_functions.borrow_mut()[&func_index]; function.set_personality_function(self.personality_func); let mut state = State::new(); @@ -8118,6 +8112,7 @@ impl ModuleCodeGenerator builder: Some(builder), alloca_builder: Some(alloca_builder), intrinsics: Some(intrinsics), + llvm_functions: self.llvm_functions.clone(), function: *function, func_sig: func_sig, locals, @@ -8238,7 +8233,7 @@ impl ModuleCodeGenerator self.signatures[*sig_id], Some(Linkage::External), ); - self.llvm_functions.insert(index, function); + self.llvm_functions.borrow_mut().insert(index, function); } self.function_signatures = Some(Arc::new(assoc)); Ok(()) diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index fe1c72d932d..b23f1b13cb1 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -3,9 +3,7 @@ use inkwell::{ builder::Builder, context::Context, module::Module, - types::{ - BasicType, FloatType, FunctionType, IntType, PointerType, StructType, VectorType, VoidType, - }, + types::{BasicType, FloatType, IntType, PointerType, StructType, VectorType, VoidType}, values::{ BasicValue, BasicValueEnum, FloatValue, FunctionValue, InstructionValue, IntValue, PointerValue, VectorValue, @@ -21,8 +19,7 @@ use wasmer_runtime_core::{ module::ModuleInfo, structures::TypedIndex, types::{ - GlobalIndex, ImportedFuncIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex, - TableIndex, Type, + GlobalIndex, ImportedFuncIndex, LocalOrImport, MemoryIndex, SigIndex, TableIndex, Type, }, units::Pages, vm::{Ctx, INTERNALS_SIZE}, @@ -895,55 +892,6 @@ impl<'a> CtxType<'a> { (base_ptr, bounds) } - pub fn local_func( - &mut self, - index: LocalFuncIndex, - fn_ty: FunctionType, - intrinsics: &Intrinsics, - module: Rc>, - builder: &Builder, - ) -> PointerValue { - let local_func_array_ptr_ptr = unsafe { - builder.build_struct_gep( - self.ctx_ptr_value, - offset_to_index(Ctx::offset_local_functions()), - "local_func_array_ptr_ptr", - ) - }; - 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, - &[intrinsics.i32_ty.const_int(index.index() as u64, false)], - "local_func_ptr_ptr", - ) - }; - 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), - "local_func_ptr", - ) - } - pub fn dynamic_sigindex(&mut self, index: SigIndex, intrinsics: &Intrinsics) -> IntValue { let (cached_sigindices, ctx_ptr_value, cache_builder) = ( &mut self.cached_sigindices, From ed6ce4b9b45d82ca4a37ba369830fa542b4f6628 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 8 Nov 2019 14:44:59 -0800 Subject: [PATCH 088/342] Don't create functions for imports, we still call those indirectly. --- lib/llvm-backend/src/code.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 4eae3aeb6e3..b2f5b62d97a 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -8228,12 +8228,14 @@ impl ModuleCodeGenerator assoc: Map, ) -> Result<(), CodegenError> { for (index, sig_id) in &assoc { - let function = self.module.borrow_mut().add_function( - &format!("fn{}", index.index()), - self.signatures[*sig_id], - Some(Linkage::External), - ); - self.llvm_functions.borrow_mut().insert(index, function); + if index.index() >= self.func_import_count { + let function = self.module.borrow_mut().add_function( + &format!("fn{}", index.index()), + self.signatures[*sig_id], + Some(Linkage::External), + ); + self.llvm_functions.borrow_mut().insert(index, function); + } } self.function_signatures = Some(Arc::new(assoc)); Ok(()) From adc9f3d47992261a8d5a00d5a9d78259f6892708 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Fri, 8 Nov 2019 16:33:08 -0800 Subject: [PATCH 089/342] Explicitly delete temp file in fd_append test --- lib/wasi-tests/wasitests/fd_append.rs | 19 +++++++++++-------- lib/wasi-tests/wasitests/fd_append.wasm | Bin 81276 -> 81710 bytes 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/wasi-tests/wasitests/fd_append.rs b/lib/wasi-tests/wasitests/fd_append.rs index f1e55c5ed9a..2e311652e4d 100644 --- a/lib/wasi-tests/wasitests/fd_append.rs +++ b/lib/wasi-tests/wasitests/fd_append.rs @@ -35,14 +35,17 @@ fn main() { file_handle.write(STR2.as_bytes()).unwrap(); } - let mut file_handle = OpenOptions::new() - .read(true) - .open(&file) - .expect("Couldn't reopen file to read"); + { + let mut file_handle = OpenOptions::new() + .read(true) + .open(&file) + .expect("Couldn't reopen file to read"); - let mut test = String::new(); - file_handle.read_to_string(&mut test); + let mut test = String::new(); + file_handle.read_to_string(&mut test); - assert_eq!(&test, &format!("{}{}", STR1, STR2)); - println!("{:?}", &test); + assert_eq!(&test, &format!("{}{}", STR1, STR2)); + println!("{:?}", &test); + } + std::fs::remove_file(&file).unwrap(); } diff --git a/lib/wasi-tests/wasitests/fd_append.wasm b/lib/wasi-tests/wasitests/fd_append.wasm index b1c73d14fabb4fb89b4b6f6b98cccaba60375200..af40f8af9c1bfb0d797456efec53ae52a84e48c8 100755 GIT binary patch delta 8280 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 PDN&Ln&s{5Ra4zwG8*0t- delta 8090 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 HPAC5#2H&xV From 7d5699c19d6d1f57200a0681ec8c7cdce954c70a Mon Sep 17 00:00:00 2001 From: losfair Date: Mon, 11 Nov 2019 01:43:01 +0800 Subject: [PATCH 090/342] Add missing instructions for aarch64. --- lib/singlepass-backend/src/emitter_x64.rs | 4 ++ .../src/translator_aarch64.rs | 64 ++++++++++++++++++- 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index 4fb4e0ebb4a..8882ef82c11 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -215,6 +215,10 @@ pub trait Emitter { fn arch_has_fneg(&self) -> bool { false } fn arch_emit_f32_neg(&mut self, _src: XMM, _dst: XMM) { unimplemented!() } fn arch_emit_f64_neg(&mut self, _src: XMM, _dst: XMM) { unimplemented!() } + + fn arch_has_xzcnt(&self) -> bool { false } + fn arch_emit_lzcnt(&mut self, _sz: Size, _src: Location, _dst: Location) { unimplemented!() } + fn arch_emit_tzcnt(&mut self, _sz: Size, _src: Location, _dst: Location) { unimplemented!() } } fn _dummy(a: &mut Assembler) { diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 5083ca84457..4530db39b6a 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -94,6 +94,14 @@ pub fn map_xmm(xmm: XMM) -> AV { XMM5 => AV(5), XMM6 => AV(6), XMM7 => AV(7), + XMM8 => AV(8), + XMM9 => AV(9), + XMM10 => AV(10), + XMM11 => AV(11), + XMM12 => AV(12), + XMM13 => AV(13), + XMM14 => AV(14), + XMM15 => AV(15), } } @@ -1195,12 +1203,22 @@ impl Emitter for Assembler { fn emit_or(&mut self, sz: Size, src: Location, dst: Location) { binop_all_nofp!(orr, self, sz, src, dst, { unreachable!("or") }); } - fn emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location) { + fn emit_bsr(&mut self, sz: Size, src: Location, dst: Location) { + unimplemented!("aarch64: bsr"); + } + fn emit_bsf(&mut self, sz: Size, src: Location, dst: Location) { + unimplemented!("aarch64: bsf"); + } + fn arch_has_xzcnt(&self) -> bool { true } + fn arch_emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location) { emit_clz_variant(self, sz, &src, &dst, false); } - fn emit_tzcnt(&mut self, sz: Size, src: Location, dst: Location) { + fn arch_emit_tzcnt(&mut self, sz: Size, src: Location, dst: Location) { emit_clz_variant(self, sz, &src, &dst, true); } + fn emit_neg(&mut self, sz: Size, value: Location) { + unimplemented!("aarch64: neg"); + } fn emit_popcnt(&mut self, sz: Size, src: Location, dst: Location) { match sz { Size::S32 => { @@ -1363,6 +1381,48 @@ impl Emitter for Assembler { } } + fn emit_xchg(&mut self, sz: Size, src: Location, dst: Location) { + unimplemented!("aarch64: xchg") + } + fn emit_lock_xadd(&mut self, sz: Size, src: Location, dst: Location) { + unimplemented!("aarch64: xadd") + } + fn emit_lock_cmpxchg(&mut self, sz: Size, src: Location, dst: Location) { + unimplemented!("aarch64: cmpxchg") + } + fn emit_vmovaps(&mut self, src: XMMOrMemory, dst: XMMOrMemory) { + unimplemented!("aarch64: vmovaps") + } + fn emit_vmovapd(&mut self, src: XMMOrMemory, dst: XMMOrMemory) { + unimplemented!("aarch64: vmovapd") + } + fn emit_vxorps(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("aarch64: vxorps") + } + fn emit_vxorpd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("aarch64: vxorpd") + } + fn emit_vcmpunordss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("aarch64: vcmpunordss") + } + fn emit_vcmpunordsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("aarch64: vcmpunordsd") + } + + fn emit_vcmpordss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("aarch64: vcmpordss") + } + fn emit_vcmpordsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { + unimplemented!("aarch64: vcmpordsd") + } + + fn emit_vblendvps(&mut self, src1: XMM, src2: XMMOrMemory, mask: XMM, dst: XMM) { + unimplemented!("aarch64: vblendvps") + } + fn emit_vblendvpd(&mut self, src1: XMM, src2: XMMOrMemory, mask: XMM, dst: XMM) { + unimplemented!("aarch64: vblendvpd") + } + avx_fn!(fadd, S, W, emit_vaddss); avx_fn!(fsub, S, W, emit_vsubss); avx_fn!(fmul, S, W, emit_vmulss); From 03a9d1ad60896502c6193b11802a5c25fba36734 Mon Sep 17 00:00:00 2001 From: losfair Date: Mon, 11 Nov 2019 01:43:16 +0800 Subject: [PATCH 091/342] Cargo fmt --- lib/runtime-core/src/fault.rs | 18 +- lib/singlepass-backend/src/emitter_x64.rs | 190 +++++++++++++----- .../src/translator_aarch64.rs | 16 +- 3 files changed, 165 insertions(+), 59 deletions(-) diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index ca6f8357a28..6471ec952c0 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -561,12 +561,18 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *mut c_void) -> F 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])); + 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 { diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index 8882ef82c11..b44fb11f60a 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -192,33 +192,81 @@ pub trait Emitter { fn emit_homomorphic_host_redirection(&mut self, target: GPR); fn emit_inline_breakpoint(&mut self, ty: InlineBreakpointType); - fn arch_has_itruncf(&self) -> bool { false } - fn arch_emit_i32_trunc_sf32(&mut self, _src: XMM, _dst: GPR) { unimplemented!() } - fn arch_emit_i32_trunc_sf64(&mut self, _src: XMM, _dst: GPR) { unimplemented!() } - fn arch_emit_i32_trunc_uf32(&mut self, _src: XMM, _dst: GPR) { unimplemented!() } - fn arch_emit_i32_trunc_uf64(&mut self, _src: XMM, _dst: GPR) { unimplemented!() } - fn arch_emit_i64_trunc_sf32(&mut self, _src: XMM, _dst: GPR) { unimplemented!() } - fn arch_emit_i64_trunc_sf64(&mut self, _src: XMM, _dst: GPR) { unimplemented!() } - fn arch_emit_i64_trunc_uf32(&mut self, _src: XMM, _dst: GPR) { unimplemented!() } - fn arch_emit_i64_trunc_uf64(&mut self, _src: XMM, _dst: GPR) { unimplemented!() } - - fn arch_has_fconverti(&self) -> bool { false } - fn arch_emit_f32_convert_si32(&mut self, _src: GPR, _dst: XMM) { unimplemented!() } - fn arch_emit_f32_convert_si64(&mut self, _src: GPR, _dst: XMM) { unimplemented!() } - fn arch_emit_f32_convert_ui32(&mut self, _src: GPR, _dst: XMM) { unimplemented!() } - fn arch_emit_f32_convert_ui64(&mut self, _src: GPR, _dst: XMM) { unimplemented!() } - fn arch_emit_f64_convert_si32(&mut self, _src: GPR, _dst: XMM) { unimplemented!() } - fn arch_emit_f64_convert_si64(&mut self, _src: GPR, _dst: XMM) { unimplemented!() } - fn arch_emit_f64_convert_ui32(&mut self, _src: GPR, _dst: XMM) { unimplemented!() } - fn arch_emit_f64_convert_ui64(&mut self, _src: GPR, _dst: XMM) { unimplemented!() } - - fn arch_has_fneg(&self) -> bool { false } - fn arch_emit_f32_neg(&mut self, _src: XMM, _dst: XMM) { unimplemented!() } - fn arch_emit_f64_neg(&mut self, _src: XMM, _dst: XMM) { unimplemented!() } - - fn arch_has_xzcnt(&self) -> bool { false } - fn arch_emit_lzcnt(&mut self, _sz: Size, _src: Location, _dst: Location) { unimplemented!() } - fn arch_emit_tzcnt(&mut self, _sz: Size, _src: Location, _dst: Location) { unimplemented!() } + fn arch_has_itruncf(&self) -> bool { + false + } + fn arch_emit_i32_trunc_sf32(&mut self, _src: XMM, _dst: GPR) { + unimplemented!() + } + fn arch_emit_i32_trunc_sf64(&mut self, _src: XMM, _dst: GPR) { + unimplemented!() + } + fn arch_emit_i32_trunc_uf32(&mut self, _src: XMM, _dst: GPR) { + unimplemented!() + } + fn arch_emit_i32_trunc_uf64(&mut self, _src: XMM, _dst: GPR) { + unimplemented!() + } + fn arch_emit_i64_trunc_sf32(&mut self, _src: XMM, _dst: GPR) { + unimplemented!() + } + fn arch_emit_i64_trunc_sf64(&mut self, _src: XMM, _dst: GPR) { + unimplemented!() + } + fn arch_emit_i64_trunc_uf32(&mut self, _src: XMM, _dst: GPR) { + unimplemented!() + } + fn arch_emit_i64_trunc_uf64(&mut self, _src: XMM, _dst: GPR) { + unimplemented!() + } + + fn arch_has_fconverti(&self) -> bool { + false + } + fn arch_emit_f32_convert_si32(&mut self, _src: GPR, _dst: XMM) { + unimplemented!() + } + fn arch_emit_f32_convert_si64(&mut self, _src: GPR, _dst: XMM) { + unimplemented!() + } + fn arch_emit_f32_convert_ui32(&mut self, _src: GPR, _dst: XMM) { + unimplemented!() + } + fn arch_emit_f32_convert_ui64(&mut self, _src: GPR, _dst: XMM) { + unimplemented!() + } + fn arch_emit_f64_convert_si32(&mut self, _src: GPR, _dst: XMM) { + unimplemented!() + } + fn arch_emit_f64_convert_si64(&mut self, _src: GPR, _dst: XMM) { + unimplemented!() + } + fn arch_emit_f64_convert_ui32(&mut self, _src: GPR, _dst: XMM) { + unimplemented!() + } + fn arch_emit_f64_convert_ui64(&mut self, _src: GPR, _dst: XMM) { + unimplemented!() + } + + fn arch_has_fneg(&self) -> bool { + false + } + fn arch_emit_f32_neg(&mut self, _src: XMM, _dst: XMM) { + unimplemented!() + } + fn arch_emit_f64_neg(&mut self, _src: XMM, _dst: XMM) { + unimplemented!() + } + + fn arch_has_xzcnt(&self) -> bool { + false + } + fn arch_emit_lzcnt(&mut self, _sz: Size, _src: Location, _dst: Location) { + unimplemented!() + } + fn arch_emit_tzcnt(&mut self, _sz: Size, _src: Location, _dst: Location) { + unimplemented!() + } } fn _dummy(a: &mut Assembler) { @@ -753,14 +801,18 @@ impl Emitter for Assembler { match (sz, src) { (Size::S64, Location::Imm32(src)) => dynasm!(self ; push src as i32), (Size::S64, Location::GPR(src)) => dynasm!(self ; push Rq(src as u8)), - (Size::S64, Location::Memory(src, disp)) => dynasm!(self ; push QWORD [Rq(src as u8) + disp]), + (Size::S64, Location::Memory(src, disp)) => { + dynasm!(self ; push QWORD [Rq(src as u8) + disp]) + } _ => panic!("singlepass can't emit PUSH {:?} {:?}", sz, src), } } fn emit_pop(&mut self, sz: Size, dst: Location) { match (sz, dst) { (Size::S64, Location::GPR(dst)) => dynasm!(self ; pop Rq(dst as u8)), - (Size::S64, Location::Memory(dst, disp)) => dynasm!(self ; pop QWORD [Rq(dst as u8) + disp]), + (Size::S64, Location::Memory(dst, disp)) => { + dynasm!(self ; pop QWORD [Rq(dst as u8) + disp]) + } _ => panic!("singlepass can't emit POP {:?} {:?}", sz, dst), } } @@ -782,13 +834,21 @@ impl Emitter for Assembler { fn emit_neg(&mut self, sz: Size, value: Location) { match (sz, value) { (Size::S8, Location::GPR(value)) => dynasm!(self ; neg Rb(value as u8)), - (Size::S8, Location::Memory(value, disp)) => dynasm!(self ; neg [Rq(value as u8) + disp]), + (Size::S8, Location::Memory(value, disp)) => { + dynasm!(self ; neg [Rq(value as u8) + disp]) + } (Size::S16, Location::GPR(value)) => dynasm!(self ; neg Rw(value as u8)), - (Size::S16, Location::Memory(value, disp)) => dynasm!(self ; neg [Rq(value as u8) + disp]), + (Size::S16, Location::Memory(value, disp)) => { + dynasm!(self ; neg [Rq(value as u8) + disp]) + } (Size::S32, Location::GPR(value)) => dynasm!(self ; neg Rd(value as u8)), - (Size::S32, Location::Memory(value, disp)) => dynasm!(self ; neg [Rq(value as u8) + disp]), + (Size::S32, Location::Memory(value, disp)) => { + dynasm!(self ; neg [Rq(value as u8) + disp]) + } (Size::S64, Location::GPR(value)) => dynasm!(self ; neg Rq(value as u8)), - (Size::S64, Location::Memory(value, disp)) => dynasm!(self ; neg [Rq(value as u8) + disp]), + (Size::S64, Location::Memory(value, disp)) => { + dynasm!(self ; neg [Rq(value as u8) + disp]) + } _ => panic!("singlepass can't emit NEG {:?} {:?}", sz, value), } } @@ -1041,18 +1101,30 @@ 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), }; } 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)), + (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), }; } @@ -1124,57 +1196,77 @@ 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)) + } } } 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)), + 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)), - XMMOrMemory::Memory(base, disp) => dynasm!(self ; ucomiss Rx(dst as u8), [Rq(base as u8) + disp]), + XMMOrMemory::Memory(base, disp) => { + dynasm!(self ; ucomiss Rx(dst as u8), [Rq(base as u8) + disp]) + } } } fn emit_ucomisd(&mut self, src: XMMOrMemory, dst: XMM) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; ucomisd Rx(dst as u8), Rx(x as u8)), - XMMOrMemory::Memory(base, disp) => dynasm!(self ; ucomisd Rx(dst as u8), [Rq(base as u8) + disp]), + XMMOrMemory::Memory(base, disp) => { + dynasm!(self ; ucomisd Rx(dst as u8), [Rq(base as u8) + disp]) + } } } fn emit_cvttss2si_32(&mut self, src: XMMOrMemory, dst: GPR) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; cvttss2si Rd(dst as u8), Rx(x as u8)), - XMMOrMemory::Memory(base, disp) => dynasm!(self ; cvttss2si Rd(dst as u8), [Rq(base as u8) + disp]), + XMMOrMemory::Memory(base, disp) => { + dynasm!(self ; cvttss2si Rd(dst as u8), [Rq(base as u8) + disp]) + } } } fn emit_cvttss2si_64(&mut self, src: XMMOrMemory, dst: GPR) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; cvttss2si Rq(dst as u8), Rx(x as u8)), - XMMOrMemory::Memory(base, disp) => dynasm!(self ; cvttss2si Rq(dst as u8), [Rq(base as u8) + disp]), + XMMOrMemory::Memory(base, disp) => { + dynasm!(self ; cvttss2si Rq(dst as u8), [Rq(base as u8) + disp]) + } } } fn emit_cvttsd2si_32(&mut self, src: XMMOrMemory, dst: GPR) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; cvttsd2si Rd(dst as u8), Rx(x as u8)), - XMMOrMemory::Memory(base, disp) => dynasm!(self ; cvttsd2si Rd(dst as u8), [Rq(base as u8) + disp]), + XMMOrMemory::Memory(base, disp) => { + dynasm!(self ; cvttsd2si Rd(dst as u8), [Rq(base as u8) + disp]) + } } } fn emit_cvttsd2si_64(&mut self, src: XMMOrMemory, dst: GPR) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; cvttsd2si Rq(dst as u8), Rx(x as u8)), - XMMOrMemory::Memory(base, disp) => dynasm!(self ; cvttsd2si Rq(dst as u8), [Rq(base as u8) + disp]), + XMMOrMemory::Memory(base, disp) => { + dynasm!(self ; cvttsd2si Rq(dst as u8), [Rq(base as u8) + disp]) + } } } diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs index 4530db39b6a..35d4fe85a08 100644 --- a/lib/singlepass-backend/src/translator_aarch64.rs +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -1209,7 +1209,9 @@ impl Emitter for Assembler { fn emit_bsf(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("aarch64: bsf"); } - fn arch_has_xzcnt(&self) -> bool { true } + fn arch_has_xzcnt(&self) -> bool { + true + } fn arch_emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location) { emit_clz_variant(self, sz, &src, &dst, false); } @@ -1461,7 +1463,9 @@ impl Emitter for Assembler { avx_fn_unop!(frintz, D, emit_vroundsd_trunc); // toward zero avx_fn_cvt!(fcvt, D, S, emit_vcvtsd2ss); - fn arch_has_itruncf(&self) -> bool { true } + fn arch_has_itruncf(&self) -> bool { + true + } fn arch_emit_i32_trunc_sf32(&mut self, src: XMM, dst: GPR) { dynasm!(self ; fcvtzs W(map_gpr(dst).x()), S(map_xmm(src).v())); } @@ -1487,7 +1491,9 @@ impl Emitter for Assembler { dynasm!(self ; fcvtzu X(map_gpr(dst).x()), D(map_xmm(src).v())); } - fn arch_has_fconverti(&self) -> bool { true } + fn arch_has_fconverti(&self) -> bool { + true + } fn arch_emit_f32_convert_si32(&mut self, src: GPR, dst: XMM) { dynasm!(self ; scvtf S(map_xmm(dst).v()), W(map_gpr(src).x())); } @@ -1513,7 +1519,9 @@ impl Emitter for Assembler { dynasm!(self ; ucvtf D(map_xmm(dst).v()), X(map_gpr(src).x())); } - fn arch_has_fneg(&self) -> bool { true } + fn arch_has_fneg(&self) -> bool { + true + } fn arch_emit_f32_neg(&mut self, src: XMM, dst: XMM) { dynasm!(self ; fneg S(map_xmm(dst).v()), S(map_xmm(src).v())); } From 03c56142032c11fedbdfccaf35e774de16fdb3f1 Mon Sep 17 00:00:00 2001 From: losfair Date: Mon, 11 Nov 2019 02:00:16 +0800 Subject: [PATCH 092/342] Rerun cargo fmt --- lib/singlepass-backend/src/codegen_x64.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index cd89b9f346f..e42a66fc1c7 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -2012,7 +2012,12 @@ impl FunctionCodeGenerator for X64FunctionCode { .as_mut() .unwrap() .insert(a.get_offset(), callback); - Self::mark_trappable(a, &self.machine, &mut self.fsm, &mut self.control_stack); + Self::mark_trappable( + a, + &self.machine, + &mut self.fsm, + &mut self.control_stack, + ); a.emit_inline_breakpoint(InlineBreakpointType::Middleware); } InternalEvent::FunctionBegin(_) | InternalEvent::FunctionEnd => {} From aad390d09ded5a2c06bde7eb58c10cd23606bc07 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 10 Nov 2019 13:13:18 -0600 Subject: [PATCH 093/342] Deny missing docs in runtime core and add missing docs --- lib/runtime-core/src/backing.rs | 5 + lib/runtime-core/src/cache.rs | 23 ++++ lib/runtime-core/src/codegen.rs | 35 +++++- lib/runtime-core/src/error.rs | 110 ++++++++++++++++-- lib/runtime-core/src/export.rs | 16 +++ lib/runtime-core/src/fault.rs | 28 +++++ lib/runtime-core/src/global.rs | 3 + lib/runtime-core/src/import.rs | 19 ++++ lib/runtime-core/src/instance.rs | 9 ++ lib/runtime-core/src/lib.rs | 19 ++++ lib/runtime-core/src/loader.rs | 17 ++- lib/runtime-core/src/macros.rs | 7 ++ lib/runtime-core/src/memory/dynamic.rs | 4 + lib/runtime-core/src/memory/mod.rs | 15 +++ lib/runtime-core/src/memory/ptr.rs | 10 ++ lib/runtime-core/src/memory/static_.rs | 4 + lib/runtime-core/src/memory/view.rs | 5 + lib/runtime-core/src/module.rs | 39 ++++++- lib/runtime-core/src/parse.rs | 10 ++ lib/runtime-core/src/state.rs | 138 ++++++++++++++++++++++- lib/runtime-core/src/structures/boxed.rs | 1 + lib/runtime-core/src/structures/map.rs | 12 ++ lib/runtime-core/src/structures/mod.rs | 2 + lib/runtime-core/src/structures/slice.rs | 7 ++ lib/runtime-core/src/sys/unix/memory.rs | 19 ++++ lib/runtime-core/src/table/anyfunc.rs | 2 + lib/runtime-core/src/table/mod.rs | 7 ++ lib/runtime-core/src/trampoline_x64.rs | 2 + lib/runtime-core/src/typed_func.rs | 25 ++++ lib/runtime-core/src/types.rs | 40 +++++++ lib/runtime-core/src/units.rs | 7 ++ lib/runtime-core/src/vm.rs | 49 ++++++++ 32 files changed, 674 insertions(+), 15 deletions(-) diff --git a/lib/runtime-core/src/backing.rs b/lib/runtime-core/src/backing.rs index ff21e9195f1..09c5743b993 100644 --- a/lib/runtime-core/src/backing.rs +++ b/lib/runtime-core/src/backing.rs @@ -17,6 +17,7 @@ use crate::{ }; use std::{fmt::Debug, slice}; +/// Size of the array for internal instance usage pub const INTERNALS_SIZE: usize = 256; pub(crate) struct Internals(pub(crate) [u64; INTERNALS_SIZE]); @@ -472,6 +473,8 @@ impl LocalBacking { } } +/// The `ImportBacking` stores references to the imported resources of an Instance. This includes +/// imported memories, tables, globals and functions. #[derive(Debug)] pub struct ImportBacking { pub(crate) memories: BoxedMap, @@ -488,6 +491,7 @@ pub struct ImportBacking { unsafe impl Send for ImportBacking {} impl ImportBacking { + /// Creates a new `ImportBacking` from the given `ModuleInner`, `ImportObject`, and `Ctx`. pub fn new( module: &ModuleInner, imports: &ImportObject, @@ -536,6 +540,7 @@ impl ImportBacking { } } + /// Gets a `ImportedFunc` from the given `ImportedFuncIndex`. pub fn imported_func(&self, index: ImportedFuncIndex) -> vm::ImportedFunc { self.vm_functions[index].clone() } diff --git a/lib/runtime-core/src/cache.rs b/lib/runtime-core/src/cache.rs index 89bbaf79665..e924cd9f5dd 100644 --- a/lib/runtime-core/src/cache.rs +++ b/lib/runtime-core/src/cache.rs @@ -1,3 +1,7 @@ +//! The cache module provides the common data structures used by compiler backends to allow +//! serializing compiled wasm code to a binary format. The binary format can be persisted, +//! and loaded to allow skipping compilation and fast startup. + use crate::{ backend::Backend, module::{Module, ModuleInfo}, @@ -6,20 +10,31 @@ use crate::{ use blake2b_simd::blake2bp; use std::{fmt, io, mem, slice}; +/// Indicates the invalid type of invalid cache file #[derive(Debug)] pub enum InvalidFileType { + /// Given cache header slice does not match the expected size of an `ArtifactHeader` InvalidSize, + /// Given cache header slice does not contain the expected magic bytes InvalidMagic, } +/// Kinds of caching errors #[derive(Debug)] pub enum Error { + /// An IO error while reading/writing a cache binary. IoError(io::Error), + /// An error deserializing bytes into a cache data structure. DeserializeError(String), + /// An error serializing bytes from a cache data structure. SerializeError(String), + /// An undefined caching error with a message. Unknown(String), + /// An invalid cache binary given. InvalidFile(InvalidFileType), + /// The cached binary has been invalidated. InvalidatedCache, + /// The current backend does not support caching. UnsupportedBackend(Backend), } @@ -164,6 +179,8 @@ struct ArtifactInner { compiled_code: Memory, } +/// Artifact are produced by caching, are serialized/deserialized to binaries, and contain +/// module info, backend metadata, and compiled code. pub struct Artifact { inner: ArtifactInner, } @@ -183,6 +200,7 @@ impl Artifact { } } + /// Deserializes an `Artifact` from the given byte slice. pub fn deserialize(bytes: &[u8]) -> Result { let (_, body_slice) = ArtifactHeader::read_from_slice(bytes)?; @@ -192,6 +210,7 @@ impl Artifact { Ok(Artifact { inner }) } + /// A reference to the `Artifact`'s stored `ModuleInfo` pub fn info(&self) -> &ModuleInfo { &self.inner.info } @@ -205,6 +224,7 @@ impl Artifact { ) } + /// Serializes the `Artifact` into a vector of bytes pub fn serialize(&self) -> Result, Error> { let cache_header = ArtifactHeader { magic: WASMER_CACHE_MAGIC, @@ -230,7 +250,9 @@ impl Artifact { /// /// The `wasmer-runtime` supplies a naive `FileSystemCache` api. pub trait Cache { + /// Error type to return when load error occurs type LoadError: fmt::Debug; + /// Error type to return when store error occurs type StoreError: fmt::Debug; /// loads a module using the default `Backend` @@ -238,6 +260,7 @@ pub trait Cache { /// loads a cached module using a specific `Backend` fn load_with_backend(&self, key: WasmHash, backend: Backend) -> Result; + /// Store a module into the cache with the given key fn store(&mut self, key: WasmHash, module: Module) -> Result<(), Self::StoreError>; } diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index 3db1b374368..e96f419e6b4 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -1,3 +1,5 @@ +//! The codegen module provides common functions and data structures used by multiple backends +//! during the code generation process. use crate::{ backend::RunnableModule, backend::{Backend, CacheGen, Compiler, CompilerConfig, Features, Token}, @@ -17,22 +19,35 @@ use std::sync::{Arc, RwLock}; use wasmparser::{self, WasmDecoder}; use wasmparser::{Operator, Type as WpType}; +/// A type that defines a function pointer, which is called when breakpoints occur. pub type BreakpointHandler = Box Result<(), Box> + Send + Sync + 'static>; + +/// Maps instruction pointers to their breakpoint handlers. pub type BreakpointMap = Arc>; +/// An event generated during parsing of a wasm binary #[derive(Debug)] pub enum Event<'a, 'b> { + /// An internal event created by the parser used to provide hooks during code generation. Internal(InternalEvent), + /// An event generated by parsing a wasm operator Wasm(&'b Operator<'a>), + /// An event generated by parsing a wasm operator that contains an owned `Operator` WasmOwned(Operator<'a>), } +/// Kinds of `InternalEvent`s created during parsing. pub enum InternalEvent { + /// A function parse is about to begin. FunctionBegin(u32), + /// A function parsing has just completed. FunctionEnd, + /// A breakpoint emitted during parsing. Breakpoint(BreakpointHandler), + /// Indicates setting an internal field. SetInternal(u32), + /// Indicates getting an internal field. GetInternal(u32), } @@ -48,10 +63,13 @@ impl fmt::Debug for InternalEvent { } } +/// Information for a breakpoint pub struct BreakpointInfo<'a> { + /// Fault. pub fault: Option<&'a dyn Any>, } +/// A trait that represents the functions needed to be implemented to generate code for a module. pub trait ModuleCodeGenerator, RM: RunnableModule, E: Debug> { /// Creates a new module code generator. fn new() -> Self; @@ -65,7 +83,7 @@ pub trait ModuleCodeGenerator, RM: RunnableModule, } /// Adds an import function. fn feed_import_function(&mut self) -> Result<(), E>; - + /// Sets the signatures. fn feed_signatures(&mut self, signatures: Map) -> Result<(), E>; /// Sets function signatures. fn feed_function_signatures(&mut self, assoc: Map) -> Result<(), E>; @@ -80,6 +98,8 @@ pub trait ModuleCodeGenerator, RM: RunnableModule, unsafe fn from_cache(cache: Artifact, _: Token) -> Result; } +/// A streaming compiler which is designed to generated code for a module based on a stream +/// of wasm parser events. pub struct StreamingCompiler< MCG: ModuleCodeGenerator, FCG: FunctionCodeGenerator, @@ -94,6 +114,7 @@ pub struct StreamingCompiler< _phantom_e: PhantomData, } +/// A simple generator for a `StreamingCompiler`. pub struct SimpleStreamingCompilerGen< MCG: ModuleCodeGenerator, FCG: FunctionCodeGenerator, @@ -113,6 +134,7 @@ impl< E: Debug, > SimpleStreamingCompilerGen { + /// Create a new `StreamingCompiler`. pub fn new() -> StreamingCompiler MiddlewareChain> { StreamingCompiler::new(|| MiddlewareChain::new()) } @@ -126,6 +148,7 @@ impl< CGEN: Fn() -> MiddlewareChain, > StreamingCompiler { + /// Create a new `StreamingCompiler` with the given `MiddlewareChain`. pub fn new(chain_gen: CGEN) -> Self { Self { middleware_chain_generator: chain_gen, @@ -137,6 +160,7 @@ impl< } } +/// Create a new `ValidatingParserConfig` with the given features. pub fn validating_parser_config(features: &Features) -> wasmparser::ValidatingParserConfig { wasmparser::ValidatingParserConfig { operator_config: wasmparser::OperatorValidatorConfig { @@ -220,29 +244,35 @@ fn requires_pre_validation(backend: Backend) -> bool { } } +/// A sink for parse events. pub struct EventSink<'a, 'b> { buffer: SmallVec<[Event<'a, 'b>; 2]>, } impl<'a, 'b> EventSink<'a, 'b> { + /// Push a new `Event` to this sink. pub fn push(&mut self, ev: Event<'a, 'b>) { self.buffer.push(ev); } } +/// A container for a chain of middlewares. pub struct MiddlewareChain { chain: Vec>, } impl MiddlewareChain { + /// Create a new empty `MiddlewareChain`. pub fn new() -> MiddlewareChain { MiddlewareChain { chain: vec![] } } + /// Push a new `FunctionMiddleware` to this `MiddlewareChain`. pub fn push(&mut self, m: M) { self.chain.push(Box::new(m)); } + /// Run this chain with the provided function code generator, event and module info. pub(crate) fn run>( &mut self, fcg: Option<&mut FCG>, @@ -270,8 +300,11 @@ impl MiddlewareChain { } } +/// A trait that represents the signature required to implement middleware for a function. pub trait FunctionMiddleware { + /// The error type for this middleware's functions. type Error: Debug; + /// Processes the given event, module info and sink. fn feed_event<'a, 'b: 'a>( &mut self, op: Event<'a, 'b>, diff --git a/lib/runtime-core/src/error.rs b/lib/runtime-core/src/error.rs index 9aac82fabfb..2847d56ead0 100644 --- a/lib/runtime-core/src/error.rs +++ b/lib/runtime-core/src/error.rs @@ -1,13 +1,22 @@ +//! The error module contains the data structures and helper functions used to implement errors that +//! are produced and returned from the wasmer runtime core. use crate::types::{FuncSig, GlobalDescriptor, MemoryDescriptor, TableDescriptor, Type}; use core::borrow::Borrow; use std::any::Any; +/// Aliases the standard `Result` type as `Result` within this module. pub type Result = std::result::Result; +/// Aliases the standard `Result` with `CompileError` as the default error type. pub type CompileResult = std::result::Result; +/// Aliases the standard `Result` with `Vec` as the default error type. pub type LinkResult = std::result::Result>; +/// Aliases the standard `Result` with `RuntimeError` as the default error type. pub type RuntimeResult = std::result::Result; +/// Aliases the standard `Result` with `CallError` as the default error type. pub type CallResult = std::result::Result; +/// Aliases the standard `Result` with `ResolveError` as the default error type. pub type ResolveResult = std::result::Result; +/// Aliases the standard `Result` with `ParseError` as the default error type. pub type ParseResult = std::result::Result; /// This is returned when the chosen compiler is unable to @@ -17,8 +26,16 @@ pub type ParseResult = std::result::Result; /// Comparing two `CompileError`s always evaluates to false. #[derive(Debug, Clone)] pub enum CompileError { - ValidationError { msg: String }, - InternalError { msg: String }, + /// A validation error containing an error message. + ValidationError { + /// An error message. + msg: String, + }, + /// A internal error containing an error message. + InternalError { + /// An error message. + msg: String, + }, } impl PartialEq for CompileError { @@ -46,41 +63,71 @@ impl std::error::Error for CompileError {} /// Comparing two `LinkError`s always evaluates to false. #[derive(Debug, Clone)] pub enum LinkError { + /// The type of the provided import does not match the expected type. IncorrectImportType { + /// Namespace. namespace: String, + /// Name. name: String, + /// Expected. expected: String, + /// Found. found: String, }, + /// The signature of the provided import does not match the expected signature. IncorrectImportSignature { + /// Namespace. namespace: String, + /// Name. name: String, + /// Expected. expected: FuncSig, + /// Found. found: FuncSig, }, + /// An expected import was not provided. ImportNotFound { + /// Namespace. namespace: String, + /// Name. name: String, }, + /// The memory descriptor provided does not match the expected descriptor. IncorrectMemoryDescriptor { + /// Namespace. namespace: String, + /// Name. name: String, + /// Expected. expected: MemoryDescriptor, + /// Found. found: MemoryDescriptor, }, + /// The table descriptor provided does not match the expected descriptor. IncorrectTableDescriptor { + /// Namespace. namespace: String, + /// Name. name: String, + /// Expected. expected: TableDescriptor, + /// Found. found: TableDescriptor, }, + /// The global descriptor provided does not match the expected descriptor. IncorrectGlobalDescriptor { + /// Namespace. namespace: String, + /// Name. name: String, + /// Expected. expected: GlobalDescriptor, + /// Found. found: GlobalDescriptor, }, + /// A generic error with a message. Generic { + /// Error message. message: String, }, } @@ -126,8 +173,16 @@ impl std::error::Error for LinkError {} /// /// Comparing two `RuntimeError`s always evaluates to false. pub enum RuntimeError { - Trap { msg: Box }, - Error { data: Box }, + /// Trap. + Trap { + /// Trap message. + msg: Box, + }, + /// Error. + Error { + /// Error data. + data: Box, + }, } impl PartialEq for RuntimeError { @@ -169,9 +224,23 @@ impl std::error::Error for RuntimeError {} /// Comparing two `ResolveError`s always evaluates to false. #[derive(Debug, Clone)] pub enum ResolveError { - Signature { expected: FuncSig, found: Vec }, - ExportNotFound { name: String }, - ExportWrongType { name: String }, + /// Found signature did not match expected signature. + Signature { + /// Expected `FuncSig`. + expected: FuncSig, + /// Found type. + found: Vec, + }, + /// Export not found. + ExportNotFound { + /// Name. + name: String, + }, + /// Export found with the wrong type. + ExportWrongType { + /// Name. + name: String, + }, } impl PartialEq for ResolveError { @@ -213,7 +282,9 @@ impl std::error::Error for ResolveError {} /// /// Comparing two `CallError`s always evaluates to false. pub enum CallError { + /// An error occured resolving the functions name or types. Resolve(ResolveError), + /// A runtime error occurred during the function call. Runtime(RuntimeError), } @@ -247,8 +318,11 @@ impl std::error::Error for CallError {} /// like a `Memory` or a `Table`. #[derive(Debug, Clone)] pub enum CreationError { + /// Unable to create memory error. UnableToCreateMemory, + /// Unable to create table error. UnableToCreateTable, + /// Invalid descriptor error with message. InvalidDescriptor(String), } @@ -281,11 +355,17 @@ impl std::error::Error for CreationError {} /// Comparing two `Error`s always evaluates to false. #[derive(Debug)] pub enum Error { + /// Compile error. CompileError(CompileError), + /// Link errors. LinkError(Vec), + /// Runtime error. RuntimeError(RuntimeError), + /// Resolve error. ResolveError(ResolveError), + /// Call error. CallError(CallError), + /// Creation error. CreationError(CreationError), } @@ -368,13 +448,20 @@ impl std::fmt::Display for Error { impl std::error::Error for Error {} +/// An error occurred while growing a memory or table. #[derive(Debug)] pub enum GrowError { + /// Error growing memory. MemoryGrowError, + /// Error growing table. TableGrowError, + /// Max pages were exceeded. ExceededMaxPages(PageError), + /// Max pages for memory were exceeded. ExceededMaxPagesForMemory(usize, usize), + /// Error protecting memory. CouldNotProtectMemory(MemoryProtectionError), + /// Error creating memory. CouldNotCreateMemory(MemoryCreationError), } @@ -393,9 +480,11 @@ impl std::fmt::Display for GrowError { impl std::error::Error for GrowError {} +/// A kind of page error. #[derive(Debug)] pub enum PageError { // left, right, added + /// Max pages were exceeded error. ExceededMaxPages(usize, usize, usize), } @@ -414,9 +503,12 @@ impl Into for PageError { } } +/// Error occured while creating memory. #[derive(Debug)] pub enum MemoryCreationError { + /// Allocation of virtual memory failed error. VirtualMemoryAllocationFailed(usize, String), + /// Error creating memory from file. CouldNotCreateMemoryFromFile(std::io::Error), } @@ -446,8 +538,10 @@ impl From for MemoryCreationError { } } +/// Error protecting memory. #[derive(Debug)] pub enum MemoryProtectionError { + /// Protection failed error. ProtectionFailed(usize, usize, String), } @@ -470,8 +564,10 @@ impl Into for MemoryProtectionError { } } +/// Parse Error. #[derive(Debug)] pub enum ParseError { + /// Error reading binary. BinaryReadError, } diff --git a/lib/runtime-core/src/export.rs b/lib/runtime-core/src/export.rs index 7960d76e699..213ea06b82f 100644 --- a/lib/runtime-core/src/export.rs +++ b/lib/runtime-core/src/export.rs @@ -1,3 +1,6 @@ +//! The export module contains the implementation data structures and helper functions used to +//! manipulate and access a wasm module's exports including memories, tables, globals, and +//! functions. use crate::{ global::Global, instance::InstanceInner, memory::Memory, module::ExportIndex, module::ModuleInner, table::Table, types::FuncSig, vm, @@ -5,27 +8,39 @@ use crate::{ use indexmap::map::Iter as IndexMapIter; use std::sync::Arc; +/// A kind of Context. #[derive(Debug, Copy, Clone)] pub enum Context { + /// External context include a mutable pointer to `Ctx`. External(*mut vm::Ctx), + /// Internal context. Internal, } // Manually implemented because context contains a raw pointer to Ctx unsafe impl Send for Context {} +/// Kind of WebAssembly export. #[derive(Debug, Clone)] pub enum Export { + /// Function export. Function { + /// A pointer to a function. func: FuncPointer, + /// A kind of context. ctx: Context, + /// The signature of the function. signature: Arc, }, + /// Memory export. Memory(Memory), + /// Table export. Table(Table), + /// Global export. Global(Global), } +/// Const pointer to a `Func`. #[derive(Debug, Clone)] pub struct FuncPointer(*const vm::Func); @@ -45,6 +60,7 @@ impl FuncPointer { } } +/// An iterator to an instance's exports. pub struct ExportIter<'a> { inner: &'a InstanceInner, iter: IndexMapIter<'a, String, ExportIndex>, diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index 5aaf81af94a..85a239783e1 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -1,4 +1,8 @@ +//! The fault module contains the implementation for handling breakpoints, traps, and signals +//! for wasm code. + pub mod raw { + //! The raw module contains required externed function interfaces for the fault module. use std::ffi::c_void; extern "C" { @@ -40,13 +44,19 @@ struct UnwindInfo { payload: Option>, // out } +/// A store for boundary register preservation. #[repr(packed)] #[derive(Default, Copy, Clone)] pub struct BoundaryRegisterPreservation { + /// R15. pub r15: u64, + /// R14. pub r14: u64, + /// R13. pub r13: u64, + /// R12. pub r12: u64, + /// RBX. pub rbx: u64, } @@ -58,6 +68,7 @@ thread_local! { static BOUNDARY_REGISTER_PRESERVATION: UnsafeCell = UnsafeCell::new(BoundaryRegisterPreservation::default()); } +/// Gets a mutable pointer to the `BoundaryRegisterPreservation`. #[no_mangle] pub unsafe extern "C" fn get_boundary_register_preservation() -> *mut BoundaryRegisterPreservation { BOUNDARY_REGISTER_PRESERVATION.with(|x| x.get()) @@ -89,10 +100,12 @@ lazy_static! { } static INTERRUPT_SIGNAL_DELIVERED: AtomicBool = AtomicBool::new(false); +/// Returns a boolean indicating if SIGINT triggered the fault. pub fn was_sigint_triggered_fault() -> bool { WAS_SIGINT_TRIGGERED.with(|x| x.get()) } +/// Runs a callback function with the given `Ctx`. pub unsafe fn with_ctx R>(ctx: *mut vm::Ctx, cb: F) -> R { let addr = CURRENT_CTX.with(|x| x.get()); let old = *addr; @@ -102,18 +115,22 @@ pub unsafe fn with_ctx R>(ctx: *mut vm::Ctx, cb: F) -> R { ret } +/// Pushes a new `CodeVersion` to the current code versions. pub fn push_code_version(version: CodeVersion) { CURRENT_CODE_VERSIONS.with(|x| x.borrow_mut().push(version)); } +/// Pops a `CodeVersion` from the current code versions. pub fn pop_code_version() -> Option { CURRENT_CODE_VERSIONS.with(|x| x.borrow_mut().pop()) } +/// Gets the wasm interrupt signal mem. pub unsafe fn get_wasm_interrupt_signal_mem() -> *mut u8 { INTERRUPT_SIGNAL_MEM.0 } +/// Sets the wasm interrupt on the given `Ctx`. pub unsafe fn set_wasm_interrupt_on_ctx(ctx: *mut vm::Ctx) { if mprotect( (&*ctx).internal.interrupt_signal_mem as _, @@ -125,6 +142,7 @@ pub unsafe fn set_wasm_interrupt_on_ctx(ctx: *mut vm::Ctx) { } } +/// Sets a wasm interrupt. pub unsafe fn set_wasm_interrupt() { let mem: *mut u8 = INTERRUPT_SIGNAL_MEM.0; if mprotect(mem as _, INTERRUPT_SIGNAL_MEM_SIZE, PROT_NONE) < 0 { @@ -132,6 +150,7 @@ pub unsafe fn set_wasm_interrupt() { } } +/// Clears the wasm interrupt. pub unsafe fn clear_wasm_interrupt() { let mem: *mut u8 = INTERRUPT_SIGNAL_MEM.0; if mprotect(mem as _, INTERRUPT_SIGNAL_MEM_SIZE, PROT_READ | PROT_WRITE) < 0 { @@ -139,6 +158,7 @@ pub unsafe fn clear_wasm_interrupt() { } } +/// Catches an unsafe unwind with the given functions and breakpoints. pub unsafe fn catch_unsafe_unwind R>( f: F, breakpoints: Option, @@ -164,6 +184,7 @@ pub unsafe fn catch_unsafe_unwind R>( } } +/// Begins an unsafe unwind. pub unsafe fn begin_unsafe_unwind(e: Box) -> ! { let unwind = UNWIND.with(|x| x.get()); let inner = (*unwind) @@ -181,6 +202,7 @@ unsafe fn with_breakpoint_map) -> R>(f: F) - f(inner.breakpoints.as_ref()) } +/// Allocates and runs with the given stack size and closure. pub fn allocate_and_run R>(size: usize, f: F) -> R { struct Context R, R> { f: Option, @@ -316,6 +338,7 @@ extern "C" fn sigint_handler( } } +/// Ensure the signal handler is installed. pub fn ensure_sighandler() { INSTALL_SIGHANDLER.call_once(|| unsafe { install_sighandler(); @@ -344,9 +367,13 @@ unsafe fn install_sighandler() { sigaction(SIGINT, &sa_interrupt).unwrap(); } +/// Info about the fault pub struct FaultInfo { + /// Faulting address. pub faulting_addr: *const c_void, + /// Instruction pointer. pub ip: *const c_void, + /// Known registers. pub known_registers: [Option; 32], } @@ -421,6 +448,7 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> } } +/// Get fault info from siginfo and ucontext. #[cfg(all(target_os = "macos", target_arch = "x86_64"))] pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> FaultInfo { #[allow(dead_code)] diff --git a/lib/runtime-core/src/global.rs b/lib/runtime-core/src/global.rs index b59d1599b8e..be9eaf6ae91 100644 --- a/lib/runtime-core/src/global.rs +++ b/lib/runtime-core/src/global.rs @@ -1,3 +1,5 @@ +//! The global module contains the implementation data structures and helper functions used to +//! manipulate and access a wasm globals. use crate::{ export::Export, import::IsExport, @@ -9,6 +11,7 @@ use std::{ sync::{Arc, Mutex}, }; +/// Container with a descriptor and a reference to a global value. pub struct Global { desc: GlobalDescriptor, storage: Arc>, diff --git a/lib/runtime-core/src/import.rs b/lib/runtime-core/src/import.rs index 9d86205b156..284ff1725a5 100644 --- a/lib/runtime-core/src/import.rs +++ b/lib/runtime-core/src/import.rs @@ -1,3 +1,6 @@ +//! The import module contains the implementation data structures and helper functions used to +//! manipulate and access a wasm module's imports including memories, tables, globals, and +//! functions. use crate::export::Export; use std::collections::VecDeque; use std::collections::{hash_map::Entry, HashMap}; @@ -7,13 +10,20 @@ use std::{ sync::{Arc, Mutex}, }; +/// This trait represents objects that act as a namespace for imports. For example, an `Instance` +/// or `ImportObject` could be considered namespaces that could provide imports to an instance. pub trait LikeNamespace { + /// Gets an export by name. fn get_export(&self, name: &str) -> Option; + /// Gets all exports in the namespace. fn get_exports(&self) -> Vec<(String, Export)>; + /// Maybe insert an `Export` by name into the namespace. fn maybe_insert(&mut self, name: &str, export: Export) -> Option<()>; } +/// A trait that represents `Export` values. pub trait IsExport { + /// Gets self as `Export`. fn to_export(&self) -> Export; } @@ -48,6 +58,8 @@ pub struct ImportObject { map: Arc>>>, pub(crate) state_creator: Option (*mut c_void, fn(*mut c_void)) + Send + Sync + 'static>>, + /// Allow missing functions to be generated and instantiation to continue when required + /// functions are not provided. pub allow_missing_functions: bool, } @@ -61,6 +73,7 @@ impl ImportObject { } } + /// Create a new `ImportObject` which generates data from the provided state creator. pub fn new_with_data(state_creator: F) -> Self where F: Fn() -> (*mut c_void, fn(*mut c_void)) + 'static + Send + Sync, @@ -145,6 +158,7 @@ impl ImportObject { .and_then(|ns| f(ns)) } + /// Create a clone ref of this namespace. pub fn clone_ref(&self) -> Self { Self { map: Arc::clone(&self.map), @@ -166,6 +180,7 @@ impl ImportObject { } } +/// Iterator for an `ImportObject`'s exports. pub struct ImportObjectIterator { elements: VecDeque<(String, String, Export)>, } @@ -204,17 +219,20 @@ impl Extend<(String, String, Export)> for ImportObject { } } +/// The top-level container for the two-level wasm imports pub struct Namespace { map: HashMap>, } impl Namespace { + /// Create a new empty `Namespace`. pub fn new() -> Self { Self { map: HashMap::new(), } } + /// Insert a new `Export` into the namespace with the given name. pub fn insert(&mut self, name: S, export: E) -> Option> where S: Into, @@ -223,6 +241,7 @@ impl Namespace { self.map.insert(name.into(), Box::new(export)) } + /// Returns true if the `Namespace` contains the given name. pub fn contains_key(&mut self, key: S) -> bool where S: Into, diff --git a/lib/runtime-core/src/instance.rs b/lib/runtime-core/src/instance.rs index 85e9f8f768b..8a8ea457d57 100644 --- a/lib/runtime-core/src/instance.rs +++ b/lib/runtime-core/src/instance.rs @@ -1,3 +1,5 @@ +//! The instance module contains the implementation data structures and helper functions used to +//! manipulate and access wasm instances. use crate::{ backend::RunnableModule, backing::{ImportBacking, LocalBacking}, @@ -48,6 +50,7 @@ impl Drop for InstanceInner { /// /// [`ImportObject`]: struct.ImportObject.html pub struct Instance { + /// Reference to the module used to instantiate this instance. pub module: Arc, inner: Pin>, #[allow(dead_code)] @@ -137,6 +140,7 @@ impl Instance { Ok(instance) } + /// Load an `Instance` using the given loader. pub fn load(&self, loader: T) -> ::std::result::Result { loader.load(&*self.module.runnable_module, &self.module.info, unsafe { &*self.inner.vmctx @@ -230,6 +234,7 @@ impl Instance { } } + /// Resolve a function by name. pub fn resolve_func(&self, name: &str) -> ResolveResult { let export_index = self.module @@ -381,10 +386,12 @@ impl Instance { Module::new(Arc::clone(&self.module)) } + /// Get the value of an internal field pub fn get_internal(&self, field: &InternalField) -> u64 { self.inner.backing.internals.0[field.index()] } + /// Set the value of an internal field. pub fn set_internal(&mut self, field: &InternalField, value: u64) { self.inner.backing.internals.0[field.index()] = value; } @@ -774,10 +781,12 @@ impl<'a> DynFunc<'a> { Ok(results) } + /// Gets the signature of this `Dynfunc`. pub fn signature(&self) -> &FuncSig { &*self.signature } + /// Gets a const pointer to the function represent by this `DynFunc`. pub fn raw(&self) -> *const vm::Func { match self.func_index.local_or_import(&self.module.info) { LocalOrImport::Local(local_func_index) => self diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index 26a76f7dbf6..d8b558ebc07 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -1,5 +1,20 @@ +//! Wasmer Runtime Core Library +//! +//! The runtime core library provides common data structures which are shared by compiler backends +//! to implement a Web Assembly runtime. +//! +//! The runtime core also provides an API for users who use wasmer as an embedded wasm runtime which +//! allows operations like compiling, instantiating, providing imports, access exports, memories, +//! and tables for example. +//! +//! The runtime core library is recommended to be used by only power users who wish to customize the +//! wasmer runtime. Most wasmer users should prefer the API which is re-exported by the wasmer +//! runtime library which provides common defaults and a friendly API. +//! + #![deny( dead_code, + missing_docs, nonstandard_style, unused_imports, unused_mut, @@ -77,6 +92,9 @@ pub use wasmparser; use self::cache::{Artifact, Error as CacheError}; pub mod prelude { + //! The prelude module is a helper module used to bring commonly used runtime core imports into + //! scope. + pub use crate::import::{ImportObject, Namespace}; pub use crate::types::{ FuncIndex, GlobalIndex, ImportedFuncIndex, ImportedGlobalIndex, ImportedMemoryIndex, @@ -158,6 +176,7 @@ pub fn validate_and_report_errors_with_features( } } +/// Creates a new module from the given cache `Artifact` for the specified compiler backend pub unsafe fn load_cache_with( cache: Artifact, compiler: &dyn backend::Compiler, diff --git a/lib/runtime-core/src/loader.rs b/lib/runtime-core/src/loader.rs index f50d3a7a032..d494863acd1 100644 --- a/lib/runtime-core/src/loader.rs +++ b/lib/runtime-core/src/loader.rs @@ -1,3 +1,4 @@ +//! The loader module functions are used to load an instance. use crate::{backend::RunnableModule, module::ModuleInfo, types::Type, types::Value, vm::Ctx}; #[cfg(unix)] use libc::{mmap, mprotect, munmap, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_READ, PROT_WRITE}; @@ -6,10 +7,14 @@ use std::{ ops::{Deref, DerefMut}, }; +/// The loader trait represents the functions used to load an instance. pub trait Loader { + /// The type of `Instance` for the loader. type Instance: Instance; + /// The error type returned by the loader. type Error: Debug; + /// Loads the given module and context into an instance. fn load( &self, rm: &dyn RunnableModule, @@ -18,18 +23,23 @@ pub trait Loader { ) -> Result; } +/// This trait represents an instance used by the loader. pub trait Instance { + /// The error type returned by this instance. type Error: Debug; + /// Call a function by id with the given args. fn call(&mut self, id: usize, args: &[Value]) -> Result; + /// Read memory at the given offset and length. fn read_memory(&mut self, _offset: u32, _len: u32) -> Result, Self::Error> { unimplemented!("Instance::read_memory") } - + /// Write memory at the given offset and length. fn write_memory(&mut self, _offset: u32, _len: u32, _buf: &[u8]) -> Result<(), Self::Error> { unimplemented!("Instance::write_memory") } } +/// A local implementation for `Loader`. pub struct LocalLoader; impl Loader for LocalLoader { @@ -54,6 +64,7 @@ impl Loader for LocalLoader { } } +/// A local instance. pub struct LocalInstance { code: CodeMemory, offsets: Vec, @@ -111,6 +122,7 @@ impl Instance for LocalInstance { } } +/// A pointer to code in memory. pub struct CodeMemory { ptr: *mut u8, size: usize, @@ -136,6 +148,7 @@ impl CodeMemory { #[cfg(unix)] impl CodeMemory { + /// Creates a new code memory with the given size. pub fn new(size: usize) -> CodeMemory { if size == 0 { return CodeMemory { @@ -167,12 +180,14 @@ impl CodeMemory { } } + /// Makes this code memory executable. pub fn make_executable(&self) { if unsafe { mprotect(self.ptr as _, self.size, PROT_READ | PROT_EXEC) } != 0 { panic!("cannot set code memory to executable"); } } + /// Makes this code memory writable. pub fn make_writable(&self) { if unsafe { mprotect(self.ptr as _, self.size, PROT_READ | PROT_WRITE) } != 0 { panic!("cannot set code memory to writable"); diff --git a/lib/runtime-core/src/macros.rs b/lib/runtime-core/src/macros.rs index 6dbb93ca09c..c4e05f97859 100644 --- a/lib/runtime-core/src/macros.rs +++ b/lib/runtime-core/src/macros.rs @@ -11,6 +11,8 @@ macro_rules! debug { }, line!(), $($arg)*)); } +/// Prints a log message with args, similar to println, when the debug feature is enabled. +/// If the debug feature is disabled, arguments are not evaluated or printed. #[macro_export] #[cfg(not(feature = "debug"))] macro_rules! debug { @@ -18,6 +20,8 @@ macro_rules! debug { ($fmt:expr, $($arg:tt)*) => {}; } +/// Prints a log message with args, similar to println, when the trace feature is enabled. +/// If the trace feature is disabled, arguments are not evaluated or printed. #[macro_export] #[cfg(feature = "trace")] macro_rules! trace { @@ -29,6 +33,8 @@ macro_rules! trace { } } +/// Prints a log message with args, similar to println, when the trace feature is enabled. +/// If the trace feature is disabled, arguments are not evaluated or printed. #[macro_export] #[cfg(not(feature = "trace"))] macro_rules! trace { @@ -36,6 +42,7 @@ macro_rules! trace { ($fmt:expr, $($arg:tt)*) => {}; } +/// Helper macro to create a new `Func` object using the provided function pointer. #[macro_export] macro_rules! func { ($func:path) => {{ diff --git a/lib/runtime-core/src/memory/dynamic.rs b/lib/runtime-core/src/memory/dynamic.rs index 332a37acb3d..885c47dbee6 100644 --- a/lib/runtime-core/src/memory/dynamic.rs +++ b/lib/runtime-core/src/memory/dynamic.rs @@ -62,10 +62,12 @@ impl DynamicMemory { Ok(storage) } + /// The size of this memory in `Pages`. pub fn size(&self) -> Pages { self.current } + /// Try to grow self by the given number of delta pages. pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Result { if delta == Pages(0) { return Ok(self.current); @@ -104,10 +106,12 @@ impl DynamicMemory { Ok(old_pages) } + /// Get this memory represented as a slice of bytes. pub fn as_slice(&self) -> &[u8] { unsafe { &self.memory.as_slice()[0..self.current.bytes().0] } } + /// Get this memory represented as a mutable slice of bytes pub fn as_slice_mut(&mut self) -> &mut [u8] { unsafe { &mut self.memory.as_slice_mut()[0..self.current.bytes().0] } } diff --git a/lib/runtime-core/src/memory/mod.rs b/lib/runtime-core/src/memory/mod.rs index 60fb87c4dd3..75a02e2276a 100644 --- a/lib/runtime-core/src/memory/mod.rs +++ b/lib/runtime-core/src/memory/mod.rs @@ -1,3 +1,5 @@ +//! The memory module contains the implementation data structures and helper functions used to +//! manipulate and access wasm memory. use crate::{ error::{CreationError, GrowError}, export::Export, @@ -170,10 +172,14 @@ impl fmt::Debug for Memory { } } +/// A kind a memory. #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum MemoryType { + /// A dynamic memory. Dynamic, + /// A static memory. Static, + /// A shared static memory. SharedStatic, } @@ -200,6 +206,7 @@ enum UnsharedMemoryStorage { Static(Box), } +/// A reference to an unshared memory. pub struct UnsharedMemory { internal: Arc, } @@ -214,6 +221,7 @@ struct UnsharedMemoryInternal { unsafe impl Sync for UnsharedMemoryInternal {} impl UnsharedMemory { + /// Create a new `UnsharedMemory` from the given memory descriptor. pub fn new(desc: MemoryDescriptor) -> Result { let mut local = vm::LocalMemory { base: std::ptr::null_mut(), @@ -243,6 +251,7 @@ impl UnsharedMemory { }) } + /// Try to grow this memory by the given number of delta pages. pub fn grow(&self, delta: Pages) -> Result { let mut storage = self.internal.storage.lock().unwrap(); @@ -260,6 +269,7 @@ impl UnsharedMemory { pages } + /// Size of this memory in pages. pub fn size(&self) -> Pages { let storage = self.internal.storage.lock().unwrap(); @@ -282,10 +292,12 @@ impl Clone for UnsharedMemory { } } +/// A reference to a shared memory. pub struct SharedMemory { internal: Arc, } +/// Data structure for a shared internal memory. pub struct SharedMemoryInternal { memory: StdMutex>, local: Cell, @@ -315,6 +327,7 @@ impl SharedMemory { }) } + /// Try to grow this memory by the given number of delta pages. pub fn grow(&self, delta: Pages) -> Result { let _guard = self.internal.lock.lock(); let mut local = self.internal.local.get(); @@ -323,12 +336,14 @@ impl SharedMemory { pages } + /// Size of this memory in pages. pub fn size(&self) -> Pages { let _guard = self.internal.lock.lock(); let memory = self.internal.memory.lock().unwrap(); memory.size() } + /// Gets a mutable pointer to the `LocalMemory`. // This function is scary, because the mutex is not locked here pub(crate) fn vm_local_memory(&self) -> *mut vm::LocalMemory { self.internal.local.as_ptr() diff --git a/lib/runtime-core/src/memory/ptr.rs b/lib/runtime-core/src/memory/ptr.rs index abed45bfb67..5e31627c20f 100644 --- a/lib/runtime-core/src/memory/ptr.rs +++ b/lib/runtime-core/src/memory/ptr.rs @@ -12,9 +12,12 @@ use crate::{ }; use std::{cell::Cell, fmt, marker::PhantomData, mem}; +/// Array. pub struct Array; +/// Item. pub struct Item; +/// A pointer to a Wasm item. #[repr(transparent)] pub struct WasmPtr { offset: u32, @@ -22,6 +25,7 @@ pub struct WasmPtr { } impl WasmPtr { + /// Create a new `WasmPtr` at the given offset. #[inline] pub fn new(offset: u32) -> Self { Self { @@ -30,6 +34,7 @@ impl WasmPtr { } } + /// Get the offset for this `WasmPtr`. #[inline] pub fn offset(self) -> u32 { self.offset @@ -44,6 +49,7 @@ fn align_pointer(ptr: usize, align: usize) -> usize { } impl WasmPtr { + /// Dereference this `WasmPtr`. #[inline] pub fn deref<'a>(self, memory: &'a Memory) -> Option<&'a Cell> { if (self.offset as usize) + mem::size_of::() >= memory.size().bytes().0 { @@ -58,6 +64,7 @@ impl WasmPtr { } } + /// Mutable dereference this `WasmPtr`. #[inline] pub unsafe fn deref_mut<'a>(self, memory: &'a Memory) -> Option<&'a mut Cell> { if (self.offset as usize) + mem::size_of::() >= memory.size().bytes().0 { @@ -72,6 +79,7 @@ impl WasmPtr { } impl WasmPtr { + /// Dereference this `WasmPtr`. #[inline] pub fn deref<'a>(self, memory: &'a Memory, index: u32, length: u32) -> Option<&'a [Cell]> { // gets the size of the item in the array with padding added such that @@ -94,6 +102,7 @@ impl WasmPtr { } } + /// Mutable dereference this `WasmPtr`. #[inline] pub unsafe fn deref_mut<'a>( self, @@ -119,6 +128,7 @@ impl WasmPtr { Some(cell_ptrs) } + /// Get a UTF-8 string representation of this `WasmPtr` with the given length. pub fn get_utf8_string<'a>(self, memory: &'a Memory, str_len: u32) -> Option<&'a str> { if self.offset as usize + str_len as usize > memory.size().bytes().0 { return None; diff --git a/lib/runtime-core/src/memory/static_.rs b/lib/runtime-core/src/memory/static_.rs index 957e53eafd7..c6355b2a2ee 100644 --- a/lib/runtime-core/src/memory/static_.rs +++ b/lib/runtime-core/src/memory/static_.rs @@ -56,10 +56,12 @@ impl StaticMemory { Ok(storage) } + /// The size of this memory in `Pages`. pub fn size(&self) -> Pages { self.current } + /// Try to grow this memory by the given number of delta pages. pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Result { if delta == Pages(0) { return Ok(self.current); @@ -94,10 +96,12 @@ impl StaticMemory { Ok(old_pages) } + /// Get this memory represented as a slice of bytes. pub fn as_slice(&self) -> &[u8] { unsafe { &self.memory.as_slice()[0..self.current.bytes().0] } } + /// Get this memory represented as a mutable slice of bytes. pub fn as_slice_mut(&mut self) -> &mut [u8] { unsafe { &mut self.memory.as_slice_mut()[0..self.current.bytes().0] } } diff --git a/lib/runtime-core/src/memory/view.rs b/lib/runtime-core/src/memory/view.rs index 4dbaa5bd52d..762e1a614b9 100644 --- a/lib/runtime-core/src/memory/view.rs +++ b/lib/runtime-core/src/memory/view.rs @@ -39,12 +39,16 @@ impl Atomic for f64 { type Output = AtomicU64; } +/// A trait that represants an atomic type. pub trait Atomicity {} +/// Atomically. pub struct Atomically; impl Atomicity for Atomically {} +/// Non-atomically. pub struct NonAtomically; impl Atomicity for NonAtomically {} +/// A view into a memory. pub struct MemoryView<'a, T: 'a, A = NonAtomically> { ptr: *mut T, length: usize, @@ -65,6 +69,7 @@ where } impl<'a, T: Atomic> MemoryView<'a, T> { + /// Get atomic access to a memory view. pub fn atomically(&self) -> MemoryView<'a, T::Output, Atomically> { MemoryView { ptr: self.ptr as *mut T::Output, diff --git a/lib/runtime-core/src/module.rs b/lib/runtime-core/src/module.rs index 1bf914a463d..eb87b85d3b9 100644 --- a/lib/runtime-core/src/module.rs +++ b/lib/runtime-core/src/module.rs @@ -1,3 +1,5 @@ +//! The module module contains the implementation data structures and helper functions used to +//! manipulate and access wasm modules. use crate::{ backend::{Backend, RunnableModule}, cache::{Artifact, Error as CacheError}, @@ -27,40 +29,59 @@ pub struct ModuleInner { pub info: ModuleInfo, } +/// Container for module data including memories, globals, tables, imports, and exports. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ModuleInfo { + /// Map of memory index to memory descriptors. // This are strictly local and the typesystem ensures that. pub memories: Map, + /// Map of global index to global descriptors. pub globals: Map, + /// Map of table index to table descriptors. pub tables: Map, + /// Map of imported function index to import name. // These are strictly imported and the typesystem ensures that. pub imported_functions: Map, + /// Map of imported memory index to import name and memory descriptor. pub imported_memories: Map, + /// Map of imported table index to import name and table descriptor. pub imported_tables: Map, + /// Map of imported global index to import name and global descriptor. pub imported_globals: Map, + /// Map of string to export index. pub exports: IndexMap, + /// Vector of data initializers. pub data_initializers: Vec, + /// Vector of table initializers. pub elem_initializers: Vec, + /// Index of optional start function. pub start_func: Option, + /// Map function index to signature index. pub func_assoc: Map, + /// Map signature index to function signature. pub signatures: Map, + /// Backend. pub backend: Backend, + /// Table of namespace indexes. pub namespace_table: StringTable, + /// Table of name indexes. pub name_table: StringTable, - /// Symbol information from emscripten + /// Symbol information from emscripten. pub em_symbol_map: Option>, + /// Custom sections. pub custom_sections: HashMap>, } impl ModuleInfo { + /// Creates custom section info from the given wasm file. pub fn import_custom_sections(&mut self, wasm: &[u8]) -> crate::error::ParseResult<()> { let mut parser = wasmparser::ModuleReader::new(wasm)?; while !parser.eof() { @@ -120,6 +141,7 @@ impl Module { Instance::new(Arc::clone(&self.inner), import_object) } + /// Create a cache artifact from this module. pub fn cache(&self) -> Result { let (backend_metadata, code) = self.inner.cache_gen.generate_cache()?; Ok(Artifact::from_parts( @@ -129,6 +151,7 @@ impl Module { )) } + /// Get the module data for this module. pub fn info(&self) -> &ModuleInfo { &self.inner.info } @@ -151,11 +174,16 @@ pub struct ImportName { pub name_index: NameIndex, } +/// Kinds of export indexes. #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] pub enum ExportIndex { + /// Function export index. Func(FuncIndex), + /// Memory export index. Memory(MemoryIndex), + /// Global export index. Global(GlobalIndex), + /// Table export index. Table(TableIndex), } @@ -182,6 +210,7 @@ pub struct TableInitializer { pub elements: Vec, } +/// String table builder. pub struct StringTableBuilder { map: IndexMap, buffer: String, @@ -189,6 +218,7 @@ pub struct StringTableBuilder { } impl StringTableBuilder { + /// Creates a new `StringTableBuilder`. pub fn new() -> Self { Self { map: IndexMap::new(), @@ -197,6 +227,7 @@ impl StringTableBuilder { } } + /// Register a new string into table. pub fn register(&mut self, s: S) -> K where S: Into + AsRef, @@ -219,6 +250,7 @@ impl StringTableBuilder { } } + /// Finish building the `StringTable`. pub fn finish(self) -> StringTable { let table = self .map @@ -233,6 +265,7 @@ impl StringTableBuilder { } } +/// A map of index to string. #[derive(Serialize, Deserialize, Debug, Clone)] pub struct StringTable { table: Map, @@ -240,6 +273,7 @@ pub struct StringTable { } impl StringTable { + /// Creates a `StringTable`. pub fn new() -> Self { Self { table: Map::new(), @@ -247,6 +281,7 @@ impl StringTable { } } + /// Gets a reference to a string at the given index. pub fn get(&self, index: K) -> &str { let (offset, length) = self.table[index]; let offset = offset as usize; @@ -256,6 +291,7 @@ impl StringTable { } } +/// Namespace index. #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct NamespaceIndex(u32); @@ -271,6 +307,7 @@ impl TypedIndex for NamespaceIndex { } } +/// Name index. #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct NameIndex(u32); diff --git a/lib/runtime-core/src/parse.rs b/lib/runtime-core/src/parse.rs index e3e2c162e1d..ab6c79cbc0d 100644 --- a/lib/runtime-core/src/parse.rs +++ b/lib/runtime-core/src/parse.rs @@ -1,3 +1,6 @@ +//! The parse module contains common data structures and functions using to parse wasm files into +//! runtime data structures. + use crate::codegen::*; use crate::{ backend::{Backend, CompilerConfig, RunnableModule}, @@ -22,9 +25,12 @@ use wasmparser::{ WasmDecoder, }; +/// Kind of load error. #[derive(Debug)] pub enum LoadError { + /// Parse error. Parse(BinaryReaderError), + /// Code generation error. Codegen(String), } @@ -42,6 +48,8 @@ impl From for LoadError { } } +/// Read wasm binary into module data using the given backend, module code generator, middlewares, +/// and compiler configuration. pub fn read_module< MCG: ModuleCodeGenerator, FCG: FunctionCodeGenerator, @@ -394,6 +402,7 @@ pub fn read_module< Ok(info) } +/// Convert given `WpType` to `Type`. pub fn wp_type_to_type(ty: WpType) -> Result { match ty { WpType::I32 => Ok(Type::I32), @@ -410,6 +419,7 @@ pub fn wp_type_to_type(ty: WpType) -> Result { } } +/// Convert given `Type` to `WpType`. pub fn type_to_wp_type(ty: Type) -> WpType { match ty { Type::I32 => WpType::I32, diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 6025abe609f..317976db500 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -1,119 +1,191 @@ +//! The state module is used to track state of a running web assembly instances so that +//! state could read or updated at runtime. Use cases include generating stack traces, switching +//! generated code from one tier to another, or serializing state of a running instace. + use std::collections::BTreeMap; use std::ops::Bound::{Included, Unbounded}; +/// An index to a register #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct RegisterIndex(pub usize); +/// A kind of wasm or constant value #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub enum WasmAbstractValue { + /// A wasm runtime value Runtime, + /// A wasm constant value Const(u64), } +/// A container for the state of a running wasm instance. #[derive(Clone, Debug)] pub struct MachineState { + /// Stack values. pub stack_values: Vec, + /// Register values. pub register_values: Vec, - + /// Previous frame. pub prev_frame: BTreeMap, - + /// Wasm stack. pub wasm_stack: Vec, + /// Private depth of the wasm stack. pub wasm_stack_private_depth: usize, - + /// Wasm instruction offset. pub wasm_inst_offset: usize, } +/// A diff of two `MachineState`s. #[derive(Clone, Debug, Default)] pub struct MachineStateDiff { + /// Last. pub last: Option, + /// Stack push. pub stack_push: Vec, + /// Stack pop. pub stack_pop: usize, + + /// Register diff. pub reg_diff: Vec<(RegisterIndex, MachineValue)>, + /// Previous frame diff. pub prev_frame_diff: BTreeMap>, // None for removal + /// Wasm stack push. pub wasm_stack_push: Vec, + /// Wasm stack pop. pub wasm_stack_pop: usize, + /// Private depth of the wasm stack. pub wasm_stack_private_depth: usize, // absolute value; not a diff. - + /// Wasm instruction offset. pub wasm_inst_offset: usize, // absolute value; not a diff. } +/// A kind of machine value. #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub enum MachineValue { + /// Undefined. Undefined, + /// Vmctx. Vmctx, + /// Vmctx Deref. VmctxDeref(Vec), + /// Preserve Register. PreserveRegister(RegisterIndex), + /// Copy Stack BP Relative. CopyStackBPRelative(i32), // relative to Base Pointer, in byte offset - ExplicitShadow, // indicates that all values above this are above the shadow region + /// Explicit Shadow. + ExplicitShadow, // indicates that all values above this are above the shadow region + /// Wasm Stack. WasmStack(usize), + /// Wasm Local. WasmLocal(usize), + /// Two Halves. TwoHalves(Box<(MachineValue, MachineValue)>), // 32-bit values. TODO: optimize: add another type for inner "half" value to avoid boxing? } +/// A map of function states. #[derive(Clone, Debug)] pub struct FunctionStateMap { + /// Initial. pub initial: MachineState, + /// Local Function Id. pub local_function_id: usize, + /// Locals. pub locals: Vec, + /// Shadow size. pub shadow_size: usize, // for single-pass backend, 32 bytes on x86-64 + /// Diffs. pub diffs: Vec, + /// Wasm Function Header target offset. pub wasm_function_header_target_offset: Option, + /// Wasm offset to target offset pub wasm_offset_to_target_offset: BTreeMap, + /// Loop offsets. pub loop_offsets: BTreeMap, /* suspend_offset -> info */ + /// Call offsets. pub call_offsets: BTreeMap, /* suspend_offset -> info */ + /// Trappable offsets. pub trappable_offsets: BTreeMap, /* suspend_offset -> info */ } +/// A kind of suspend offset. #[derive(Clone, Copy, Debug)] pub enum SuspendOffset { + /// A loop. Loop(usize), + /// A call. Call(usize), + /// A trappable. Trappable(usize), } +/// Info for an offset. #[derive(Clone, Debug)] pub struct OffsetInfo { + /// End offset. pub end_offset: usize, // excluded bound + /// Diff Id. pub diff_id: usize, + /// Activate offset. pub activate_offset: usize, } +/// A map of module state. #[derive(Clone, Debug)] pub struct ModuleStateMap { + /// Local functions. pub local_functions: BTreeMap, + /// Total size. pub total_size: usize, } +/// State dump of a wasm function. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct WasmFunctionStateDump { + /// Local function id. pub local_function_id: usize, + /// Wasm instruction offset. pub wasm_inst_offset: usize, + /// Stack. pub stack: Vec>, + /// Locals. pub locals: Vec>, } +/// An image of the execution state. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ExecutionStateImage { + /// Frames. pub frames: Vec, } +/// Represents an image of an `Instance` including its memory, globals, and execution state. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct InstanceImage { + /// Memory for this `InstanceImage` pub memory: Option>, + /// Stored globals for this `InstanceImage` pub globals: Vec, + /// `ExecutionStateImage` for this `InstanceImage` pub execution_state: ExecutionStateImage, } +/// A `CodeVersion` is a container for a unit of generated code for a module. #[derive(Debug, Clone)] pub struct CodeVersion { + /// Indicates if this code version is the baseline version. pub baseline: bool, + + /// `ModuleStateMap` for this code version. pub msm: ModuleStateMap, + + /// A pointer to the machine code for this module. pub base: usize, } impl ModuleStateMap { + /// Looks up an ip from self using the given ip, base, and offset table provider. pub fn lookup_ip &BTreeMap>( &self, ip: usize, @@ -146,6 +218,7 @@ impl ModuleStateMap { } } } + /// Looks up a call ip from self using the given ip and base values. pub fn lookup_call_ip( &self, ip: usize, @@ -154,6 +227,7 @@ impl ModuleStateMap { self.lookup_ip(ip, base, |fsm| &fsm.call_offsets) } + /// Looks up a trappable ip from self using the given ip and base values. pub fn lookup_trappable_ip( &self, ip: usize, @@ -162,6 +236,7 @@ impl ModuleStateMap { self.lookup_ip(ip, base, |fsm| &fsm.trappable_offsets) } + /// Looks up a loop ip from self using the given ip and base values. pub fn lookup_loop_ip( &self, ip: usize, @@ -172,6 +247,7 @@ impl ModuleStateMap { } impl FunctionStateMap { + /// Creates a new `FunctionStateMap` with the given parameters. pub fn new( initial: MachineState, local_function_id: usize, @@ -194,6 +270,7 @@ impl FunctionStateMap { } impl MachineState { + /// Creates a `MachineStateDiff` from self and the given `&MachineState`. pub fn diff(&self, old: &MachineState) -> MachineStateDiff { let first_diff_stack_depth: usize = self .stack_values @@ -256,6 +333,7 @@ impl MachineState { } impl MachineStateDiff { + /// Creates a `MachineState` from the given `&FunctionStateMap`. pub fn build_state(&self, m: &FunctionStateMap) -> MachineState { let mut chain: Vec<&MachineStateDiff> = vec![]; chain.push(self); @@ -298,6 +376,7 @@ impl MachineStateDiff { } impl ExecutionStateImage { + /// Prints a backtrace if the `WASMER_BACKTRACE` environment variable is 1. pub fn print_backtrace_if_needed(&self) { use std::env; @@ -311,6 +390,7 @@ impl ExecutionStateImage { eprintln!("Run with `WASMER_BACKTRACE=1` environment variable to display a backtrace."); } + /// Converts self into a `String`, used for display purposes. pub fn output(&self) -> String { fn join_strings(x: impl Iterator, sep: &str) -> String { let mut ret = String::new(); @@ -376,6 +456,7 @@ impl ExecutionStateImage { } impl InstanceImage { + /// Converts a slice of bytes into an `Option` pub fn from_bytes(input: &[u8]) -> Option { use bincode::deserialize; match deserialize(input) { @@ -384,6 +465,7 @@ impl InstanceImage { } } + /// Converts self into a vector of bytes. pub fn to_bytes(&self) -> Vec { use bincode::serialize; serialize(self).unwrap() @@ -392,6 +474,7 @@ impl InstanceImage { #[cfg(all(unix, target_arch = "x86_64"))] pub mod x64 { + //! The x64 state module contains functions to generate state and code for x64 targets. use super::*; use crate::codegen::BreakpointMap; use crate::fault::{ @@ -410,6 +493,7 @@ pub mod x64 { ptr as usize as u64 } + /// Create a new `MachineState` with default values. pub fn new_machine_state() -> MachineState { MachineState { stack_values: vec![], @@ -421,6 +505,8 @@ pub mod x64 { } } + /// Invokes a call return on the stack for the given module state map, code base, instance + /// image and context. #[warn(unused_variables)] pub unsafe fn invoke_call_return_on_stack( msm: &ModuleStateMap, @@ -772,6 +858,7 @@ pub mod x64 { ) } + /// Builds an `InstanceImage` for the given `Ctx` and `ExecutionStateImage`. pub fn build_instance_image( vmctx: &mut Ctx, execution_state: ExecutionStateImage, @@ -807,6 +894,8 @@ pub mod x64 { } } + /// Returns a `ExecutionStateImage` for the given versions, stack, initial registers and + /// initial address. #[warn(unused_variables)] pub unsafe fn read_stack<'a, I: Iterator, F: Fn() -> I + 'a>( versions: F, @@ -1022,55 +1111,93 @@ pub mod x64 { unreachable!(); } + /// A kind of GPR register #[repr(u8)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum GPR { + /// RAX Register RAX, + /// RCX Register RCX, + /// RDX Register RDX, + /// RBX Register RBX, + /// RSP Register RSP, + /// RBP Register RBP, + /// RSI Register RSI, + /// RDI Register RDI, + /// R8 Register R8, + /// R9 Register R9, + /// R10 Register R10, + /// R11 Register R11, + /// R12 Register R12, + /// R13 Register R13, + /// R14 Register R14, + /// R15 Register R15, } + /// A kind of XMM register #[repr(u8)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum XMM { + /// XMM0 Register XMM0, + /// XMM1 Register XMM1, + /// XMM2 Register XMM2, + /// XMM3 Register XMM3, + /// XMM4 Register XMM4, + /// XMM5 Register XMM5, + /// XMM6 Register XMM6, + /// XMM7 Register XMM7, + /// XMM8 Register XMM8, + /// XMM9 Register XMM9, + /// XMM10 Register XMM10, + /// XMM11 Register XMM11, + /// XMM12 Register XMM12, + /// XMM13 Register XMM13, + /// XMM14 Register XMM14, + /// XMM15 Register XMM15, } + /// A kind of register belonging to the x64 register set #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum X64Register { + /// A register belonging to the GPR register set GPR(GPR), + /// A register belonging to the XMM register set XMM(XMM), } impl X64Register { + /// Returns a `RegisterIndex` for the current `X64Register`. pub fn to_index(&self) -> RegisterIndex { match *self { X64Register::GPR(x) => RegisterIndex(x as usize), @@ -1078,6 +1205,7 @@ pub mod x64 { } } + /// Returns an `Option` for the given DWARF register integer number. pub fn from_dwarf_regnum(x: u16) -> Option { Some(match x { 0 => X64Register::GPR(GPR::RAX), diff --git a/lib/runtime-core/src/structures/boxed.rs b/lib/runtime-core/src/structures/boxed.rs index 710dc70a6a4..439bad68075 100644 --- a/lib/runtime-core/src/structures/boxed.rs +++ b/lib/runtime-core/src/structures/boxed.rs @@ -5,6 +5,7 @@ use std::{ ops::{Deref, DerefMut}, }; +/// Boxed map. #[derive(Debug, Clone)] pub struct BoxedMap where diff --git a/lib/runtime-core/src/structures/map.rs b/lib/runtime-core/src/structures/map.rs index 2d4f3323edd..b3f20b5cb44 100644 --- a/lib/runtime-core/src/structures/map.rs +++ b/lib/runtime-core/src/structures/map.rs @@ -21,6 +21,7 @@ impl Map where K: TypedIndex, { + /// Creates a new `Map`. pub fn new() -> Self { Self { elems: Vec::new(), @@ -28,6 +29,7 @@ where } } + /// Creates a new empty `Map` with the given capacity. pub fn with_capacity(capacity: usize) -> Self { Self { elems: Vec::with_capacity(capacity), @@ -35,32 +37,39 @@ where } } + /// Returns the size of this map. pub fn len(&self) -> usize { self.elems.len() } + /// Returns true if this map is empty. pub fn is_empty(&self) -> bool { self.elems.is_empty() } + /// Adds a new value to this map. pub fn push(&mut self, value: V) -> K { let len = self.len(); self.elems.push(value); K::new(len) } + /// Returns the next index into the map. pub fn next_index(&self) -> K { K::new(self.len()) } + /// Reserves the given size. pub fn reserve_exact(&mut self, size: usize) { self.elems.reserve_exact(size); } + /// Convert this into a `BoxedMap`. pub fn into_boxed_map(self) -> BoxedMap { BoxedMap::new(self.elems.into_boxed_slice()) } + /// Convert this into a `Vec`. pub fn into_vec(self) -> Vec { self.elems } @@ -71,6 +80,7 @@ where K: TypedIndex, V: Clone, { + /// Resize this map to the given new length and value. pub fn resize(&mut self, new_len: usize, value: V) { self.elems.resize(new_len, value); } @@ -184,6 +194,7 @@ where } } +/// Iterator for a `Map`. pub struct Iter<'a, K: TypedIndex, V: 'a> { enumerated: iter::Enumerate>, _marker: PhantomData, @@ -206,6 +217,7 @@ impl<'a, K: TypedIndex, V: 'a> Iterator for Iter<'a, K, V> { } } +/// Mutable iterator for a `Map`. pub struct IterMut<'a, K: TypedIndex, V: 'a> { enumerated: iter::Enumerate>, _marker: PhantomData, diff --git a/lib/runtime-core/src/structures/mod.rs b/lib/runtime-core/src/structures/mod.rs index ca7a449dfdc..42af0d2c07a 100644 --- a/lib/runtime-core/src/structures/mod.rs +++ b/lib/runtime-core/src/structures/mod.rs @@ -1,3 +1,4 @@ +//! The structures module contains commonly used data structures. mod boxed; mod map; mod slice; @@ -6,6 +7,7 @@ pub use self::boxed::BoxedMap; pub use self::map::{Iter, IterMut, Map}; pub use self::slice::SliceMap; +/// Represents a typed index. pub trait TypedIndex: Copy + Clone { #[doc(hidden)] fn new(index: usize) -> Self; diff --git a/lib/runtime-core/src/structures/slice.rs b/lib/runtime-core/src/structures/slice.rs index 8574b2d5bc0..5ac0d6190a5 100644 --- a/lib/runtime-core/src/structures/slice.rs +++ b/lib/runtime-core/src/structures/slice.rs @@ -20,30 +20,37 @@ impl SliceMap where K: TypedIndex, { + /// Gets a reference to the value at the given index. pub fn get(&self, index: K) -> Option<&V> { self.slice.get(index.index()) } + /// Gets a mutable reference to the value at the given index. pub fn get_mut(&mut self, index: K) -> Option<&mut V> { self.slice.get_mut(index.index()) } + /// Gets the length of this slice map. pub fn len(&self) -> usize { self.slice.len() } + /// Returns an iterator for this slice map. pub fn iter(&self) -> Iter { Iter::new(self.slice.iter()) } + /// Returns a mutable iterator for this slice map. pub fn iter_mut(&mut self) -> IterMut { IterMut::new(self.slice.iter_mut()) } + /// Gets a pointer to the `SliceMap`. pub fn as_ptr(&self) -> *const V { self as *const SliceMap as *const V } + /// Gets a mutable pointer to the `SliceMap`. pub fn as_mut_ptr(&mut self) -> *mut V { self as *mut SliceMap as *mut V } diff --git a/lib/runtime-core/src/sys/unix/memory.rs b/lib/runtime-core/src/sys/unix/memory.rs index fc60d732b6f..e0c2a6705cb 100644 --- a/lib/runtime-core/src/sys/unix/memory.rs +++ b/lib/runtime-core/src/sys/unix/memory.rs @@ -9,6 +9,7 @@ use std::{fs::File, os::unix::io::IntoRawFd, path::Path, ptr, slice, sync::Arc}; unsafe impl Send for Memory {} unsafe impl Sync for Memory {} +/// Data for a sized and protected region of memory. #[derive(Debug)] pub struct Memory { ptr: *mut u8, @@ -18,6 +19,7 @@ pub struct Memory { } impl Memory { + /// Create a new memory from the given path value and protection. pub fn from_file_path