From 12f8f3d08509478f7988e49e2e0ca30204d46ffd Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Tue, 30 Jul 2019 14:47:53 -0700 Subject: [PATCH 1/6] First working version of LLVM in Windows --- .appveyor.yml | 19 +++-- Cargo.lock | 6 +- lib/llvm-backend/Cargo.toml | 12 +++- lib/llvm-backend/cpp/object_loader.cpp | 8 +-- lib/llvm-backend/src/backend.rs | 96 ++----------------------- lib/llvm-backend/src/lib.rs | 1 + lib/llvm-backend/src/platform/common.rs | 3 + lib/llvm-backend/src/platform/mod.rs | 9 ++- lib/llvm-backend/src/platform/unix.rs | 63 ++++++++++++++++ lib/llvm-backend/src/platform/win.rs | 80 +++++++++++++++++++++ lib/llvm-backend/src/structs.rs | 39 ++++++++++ lib/runtime/Cargo.toml | 2 +- 12 files changed, 227 insertions(+), 111 deletions(-) create mode 100644 lib/llvm-backend/src/platform/common.rs create mode 100644 lib/llvm-backend/src/platform/win.rs create mode 100644 lib/llvm-backend/src/structs.rs diff --git a/.appveyor.yml b/.appveyor.yml index 4b94ce48915..408f98a21af 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -21,21 +21,20 @@ cache: - wapm-cli-target install: - # # Install LLVM - # - mkdir C:\projects\deps - # - cd C:\projects\deps - # - appveyor DownloadFile https://prereleases.llvm.org/win-snapshots/LLVM-8.0.0-r351033-win64.exe -FileName llvm.exe - # - 7z x llvm.exe -oC:\projects\deps\llvm - # # - set "PATH=%PATH%;C:\projects\deps\llvm\bin" - # - set "LLD_LINK=C:\projects\deps\llvm\bin\lld-link.exe" - # - set "LLVM_SYS_80_PREFIX=C:\projects\deps\llvm" - # - cd "%APPVEYOR_BUILD_FOLDER%" + # Install LLVM + - mkdir C:\projects\deps + - cd C:\projects\deps + - appveyor DownloadFile https://github.com/wasmerio/windows-llvm-build/releases/download/v8.0.0/llvm-8.0.0-install.zip -FileName llvm-8.0.0-install.zip + - 7z x llvm-8.0.0-install.zip + - C:\projects\deps\llvm-8.0.0-install\bin\llvm-config.exe --version + - set "LLVM_SYS_80_PREFIX=C:\projects\deps\llvm-8.0.0-install" + - cd "%APPVEYOR_BUILD_FOLDER%" # Install Rust # uncomment these lines if the cache is cleared, or if we must re-install rust for some reason # - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe # - rustup-init.exe -yv --default-host %target% - - set PATH=%PATH%;C:\\Libraries\\llvm-5.0.0\\bin;%USERPROFILE%\.cargo\bin + - set PATH=%PATH%;%USERPROFILE%\.cargo\bin - rustup default stable-%target% - rustup update - rustc -vV diff --git a/Cargo.lock b/Cargo.lock index c3af0bd1bb8..ca701633ca8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -565,19 +565,20 @@ source = "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#f1775622b6d88fd30006b377042726854c9e0193" +source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#4c5359e507b8a3439c9e2c7fff5c336224069638" 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)", "libc 0.2.57 (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.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "inkwell_internal_macros" version = "0.1.0" -source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#f1775622b6d88fd30006b377042726854c9e0193" +source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#4c5359e507b8a3439c9e2c7fff5c336224069638" dependencies = [ "cargo_toml 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1522,6 +1523,7 @@ dependencies = [ "wabt 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime-core 0.5.7", "wasmparser 0.34.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/lib/llvm-backend/Cargo.toml b/lib/llvm-backend/Cargo.toml index 30d125917a6..64c3475fb4c 100644 --- a/lib/llvm-backend/Cargo.toml +++ b/lib/llvm-backend/Cargo.toml @@ -1,13 +1,12 @@ [package] name = "wasmer-llvm-backend" version = "0.5.7" -authors = ["Lachlan Sneff "] +authors = ["The Wasmer Engineering Team "] edition = "2018" readme = "README.md" [dependencies] wasmer-runtime-core = { path = "../runtime-core", version = "0.5.7" } -inkwell = { git = "https://github.com/wasmerio/inkwell", branch = "llvm8-0", features = ["llvm8-0"] } wasmparser = "0.34.0" hashbrown = "0.1.8" smallvec = "0.6.8" @@ -16,6 +15,15 @@ libc = "0.2.49" nix = "0.14.0" capstone = { version = "0.5.0", optional = true } +[dependencies.inkwell] +git = "https://github.com/wasmerio/inkwell" +branch = "llvm8-0" +default-features = false +features = ["llvm8-0", "target-x86"] + +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3", features = ["memoryapi"] } + [build-dependencies] cc = "1.0" lazy_static = "1.2.0" diff --git a/lib/llvm-backend/cpp/object_loader.cpp b/lib/llvm-backend/cpp/object_loader.cpp index 3f2078c84f2..3ec3f5d1a7f 100644 --- a/lib/llvm-backend/cpp/object_loader.cpp +++ b/lib/llvm-backend/cpp/object_loader.cpp @@ -75,16 +75,16 @@ struct MemoryManager : llvm::RuntimeDyld::MemoryManager { } virtual void registerEHFrames(uint8_t* addr, uint64_t LoadAddr, size_t size) override { - eh_frame_ptr = addr; + /* eh_frame_ptr = addr; eh_frame_size = size; eh_frames_registered = true; - callbacks.visit_fde(addr, size, __register_frame); + callbacks.visit_fde(addr, size, __register_frame);*/ } virtual void deregisterEHFrames() override { - if (eh_frames_registered) { + /* if (eh_frames_registered) { callbacks.visit_fde(eh_frame_ptr, eh_frame_size, __deregister_frame); - } + }*/ } virtual bool finalizeMemory(std::string *ErrMsg = nullptr) override { diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index 7a8c6c64ac8..ff8c281df9a 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -1,14 +1,12 @@ use crate::intrinsics::Intrinsics; +use crate::structs::{Callbacks, LLVMModule, LLVMResult, MemProtect}; use inkwell::{ memory_buffer::MemoryBuffer, module::Module, targets::{CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetMachine}, OptimizationLevel, }; -use libc::{ - c_char, mmap, mprotect, munmap, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_NONE, PROT_READ, - PROT_WRITE, -}; +use libc::c_char; use std::{ any::Any, ffi::{c_void, CString}, @@ -31,42 +29,6 @@ use wasmer_runtime_core::{ vm, vmcalls, }; -#[repr(C)] -struct LLVMModule { - _private: [u8; 0], -} - -#[allow(non_camel_case_types, dead_code)] -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -#[repr(C)] -enum MemProtect { - NONE, - READ, - READ_WRITE, - READ_EXECUTE, -} - -#[allow(non_camel_case_types, dead_code)] -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -#[repr(C)] -enum LLVMResult { - OK, - ALLOCATE_FAILURE, - PROTECT_FAILURE, - DEALLOC_FAILURE, - OBJECT_LOAD_FAILURE, -} - -#[repr(C)] -struct Callbacks { - alloc_memory: extern "C" fn(usize, MemProtect, &mut *mut u8, &mut usize) -> LLVMResult, - protect_memory: extern "C" fn(*mut u8, usize, MemProtect) -> LLVMResult, - dealloc_memory: extern "C" fn(*mut u8, usize) -> LLVMResult, - - lookup_vm_symbol: extern "C" fn(*const c_char, usize) -> *const vm::Func, - visit_fde: extern "C" fn(*mut u8, usize, extern "C" fn(*mut u8)), -} - extern "C" { fn module_load( mem_ptr: *const u8, @@ -99,69 +61,21 @@ extern "C" { } fn get_callbacks() -> Callbacks { - fn round_up_to_page_size(size: usize) -> usize { - (size + (4096 - 1)) & !(4096 - 1) - } - extern "C" fn alloc_memory( size: usize, protect: MemProtect, ptr_out: &mut *mut u8, size_out: &mut usize, ) -> LLVMResult { - let size = round_up_to_page_size(size); - let ptr = unsafe { - mmap( - ptr::null_mut(), - size, - match protect { - MemProtect::NONE => PROT_NONE, - MemProtect::READ => PROT_READ, - MemProtect::READ_WRITE => PROT_READ | PROT_WRITE, - MemProtect::READ_EXECUTE => PROT_READ | PROT_EXEC, - }, - MAP_PRIVATE | MAP_ANON, - -1, - 0, - ) - }; - if ptr as isize == -1 { - return LLVMResult::ALLOCATE_FAILURE; - } - *ptr_out = ptr as _; - *size_out = size; - LLVMResult::OK + unsafe { crate::platform::alloc_memory(size, protect, ptr_out, size_out) } } extern "C" fn protect_memory(ptr: *mut u8, size: usize, protect: MemProtect) -> LLVMResult { - let res = unsafe { - mprotect( - ptr as _, - round_up_to_page_size(size), - match protect { - MemProtect::NONE => PROT_NONE, - MemProtect::READ => PROT_READ, - MemProtect::READ_WRITE => PROT_READ | PROT_WRITE, - MemProtect::READ_EXECUTE => PROT_READ | PROT_EXEC, - }, - ) - }; - - if res == 0 { - LLVMResult::OK - } else { - LLVMResult::PROTECT_FAILURE - } + unsafe { crate::platform::protect_memory(ptr, size, protect) } } extern "C" fn dealloc_memory(ptr: *mut u8, size: usize) -> LLVMResult { - let res = unsafe { munmap(ptr as _, round_up_to_page_size(size)) }; - - if res == 0 { - LLVMResult::OK - } else { - LLVMResult::DEALLOC_FAILURE - } + unsafe { crate::platform::dealloc_memory(ptr, size) } } extern "C" fn lookup_vm_symbol(name_ptr: *const c_char, length: usize) -> *const vm::Func { diff --git a/lib/llvm-backend/src/lib.rs b/lib/llvm-backend/src/lib.rs index 0c6d00006d8..9d7a7acf5d0 100644 --- a/lib/llvm-backend/src/lib.rs +++ b/lib/llvm-backend/src/lib.rs @@ -7,6 +7,7 @@ mod intrinsics; mod platform; mod read_info; mod state; +mod structs; mod trampolines; pub use code::LLVMFunctionCodeGenerator as FunctionCodeGenerator; diff --git a/lib/llvm-backend/src/platform/common.rs b/lib/llvm-backend/src/platform/common.rs new file mode 100644 index 00000000000..7fcd8493e85 --- /dev/null +++ b/lib/llvm-backend/src/platform/common.rs @@ -0,0 +1,3 @@ +pub fn round_up_to_page_size(size: usize) -> usize { + (size + (4096 - 1)) & !(4096 - 1) +} diff --git a/lib/llvm-backend/src/platform/mod.rs b/lib/llvm-backend/src/platform/mod.rs index 01b81b022e2..b61d0b57e75 100644 --- a/lib/llvm-backend/src/platform/mod.rs +++ b/lib/llvm-backend/src/platform/mod.rs @@ -1,7 +1,14 @@ +mod common; + #[cfg(unix)] mod unix; #[cfg(unix)] pub use self::unix::*; #[cfg(target_family = "windows")] -compile_error!("windows not yet supported for the llvm-based compiler backend"); +mod win; +#[cfg(target_family = "windows")] +pub use self::win::*; + +#[cfg(not(any(unix, target_family = "windows")))] +compile_error!("Your system is not yet supported for the llvm-based compiler backend"); diff --git a/lib/llvm-backend/src/platform/unix.rs b/lib/llvm-backend/src/platform/unix.rs index d16384179c1..61e8af76a96 100644 --- a/lib/llvm-backend/src/platform/unix.rs +++ b/lib/llvm-backend/src/platform/unix.rs @@ -1,3 +1,9 @@ +use super::common::round_up_to_page_size; +use crate::structs::{LLVMResult, MemProtect}; +use libc::{ + c_char, mmap, mprotect, munmap, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_NONE, PROT_READ, + PROT_WRITE, +}; use libc::{c_void, siginfo_t}; use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, SIGBUS, SIGSEGV}; @@ -68,3 +74,60 @@ extern "C" fn signal_trap_handler( throw_trap(2); } } + +pub unsafe fn alloc_memory( + size: usize, + protect: MemProtect, + ptr_out: &mut *mut u8, + size_out: &mut usize, +) -> LLVMResult { + let size = round_up_to_page_size(size); + let ptr = mmap( + ptr::null_mut(), + size, + match protect { + MemProtect::NONE => PROT_NONE, + MemProtect::READ => PROT_READ, + MemProtect::READ_WRITE => PROT_READ | PROT_WRITE, + MemProtect::READ_EXECUTE => PROT_READ | PROT_EXEC, + }, + MAP_PRIVATE | MAP_ANON, + -1, + 0, + ); + if ptr as isize == -1 { + return LLVMResult::ALLOCATE_FAILURE; + } + *ptr_out = ptr as _; + *size_out = size; + LLVMResult::OK +} + +pub unsafe fn protect_memory(ptr: *mut u8, size: usize, protect: MemProtect) -> LLVMResult { + let res = mprotect( + ptr as _, + round_up_to_page_size(size), + match protect { + MemProtect::NONE => PROT_NONE, + MemProtect::READ => PROT_READ, + MemProtect::READ_WRITE => PROT_READ | PROT_WRITE, + MemProtect::READ_EXECUTE => PROT_READ | PROT_EXEC, + }, + ); + + if res == 0 { + LLVMResult::OK + } else { + LLVMResult::PROTECT_FAILURE + } +} + +pub unsafe fn dealloc_memory(ptr: *mut u8, size: usize) -> LLVMResult { + let res = munmap(ptr as _, round_up_to_page_size(size)); + + if res == 0 { + LLVMResult::OK + } else { + LLVMResult::DEALLOC_FAILURE + } +} diff --git a/lib/llvm-backend/src/platform/win.rs b/lib/llvm-backend/src/platform/win.rs new file mode 100644 index 00000000000..88315fd24a8 --- /dev/null +++ b/lib/llvm-backend/src/platform/win.rs @@ -0,0 +1,80 @@ +use super::common::round_up_to_page_size; +use crate::structs::{LLVMResult, MemProtect}; +use std::ptr; + +use winapi::um::memoryapi::{VirtualAlloc, VirtualFree}; +use winapi::um::winnt::{ + MEM_COMMIT, MEM_DECOMMIT, MEM_RESERVE, PAGE_EXECUTE_READ, PAGE_NOACCESS, PAGE_READONLY, + PAGE_READWRITE, +}; + +pub unsafe fn visit_fde(_addr: *mut u8, _size: usize, _visitor: extern "C" fn(*mut u8)) { + // Do nothing on Windows +} + +pub unsafe fn install_signal_handler() { + // Do nothing on Windows +} + +pub unsafe fn alloc_memory( + size: usize, + protect: MemProtect, + ptr_out: &mut *mut u8, + size_out: &mut usize, +) -> LLVMResult { + let size = round_up_to_page_size(size); + let flags = if protect == MemProtect::NONE { + MEM_RESERVE + } else { + MEM_RESERVE | MEM_COMMIT + }; + let ptr = VirtualAlloc( + ptr::null_mut(), + size, + flags, + memprotect_to_protect_const(protect), + ); + + if ptr.is_null() { + return LLVMResult::ALLOCATE_FAILURE; + } + + *ptr_out = ptr as _; + *size_out = size; + LLVMResult::OK +} + +pub unsafe fn protect_memory(ptr: *mut u8, size: usize, protect: MemProtect) -> LLVMResult { + let size = round_up_to_page_size(size); + let ptr = VirtualAlloc( + ptr as _, + size, + MEM_COMMIT, + memprotect_to_protect_const(protect), + ); + + if ptr.is_null() { + LLVMResult::PROTECT_FAILURE + } else { + LLVMResult::OK + } +} + +pub unsafe fn dealloc_memory(ptr: *mut u8, size: usize) -> LLVMResult { + let success = VirtualFree(ptr as _, size, MEM_DECOMMIT); + // If the function succeeds, the return value is nonzero. + if success == 1 { + LLVMResult::OK + } else { + LLVMResult::DEALLOC_FAILURE + } +} + +fn memprotect_to_protect_const(protect: MemProtect) -> u32 { + match protect { + MemProtect::NONE => PAGE_NOACCESS, + MemProtect::READ => PAGE_READONLY, + MemProtect::READ_WRITE => PAGE_READWRITE, + MemProtect::READ_EXECUTE => PAGE_EXECUTE_READ, + } +} diff --git a/lib/llvm-backend/src/structs.rs b/lib/llvm-backend/src/structs.rs new file mode 100644 index 00000000000..0aa2b6e9cb6 --- /dev/null +++ b/lib/llvm-backend/src/structs.rs @@ -0,0 +1,39 @@ +use libc::c_char; + +use wasmer_runtime_core::vm; + +#[repr(C)] +pub struct LLVMModule { + _private: [u8; 0], +} + +#[allow(non_camel_case_types, dead_code)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[repr(C)] +pub enum MemProtect { + NONE, + READ, + READ_WRITE, + READ_EXECUTE, +} + +#[allow(non_camel_case_types, dead_code)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[repr(C)] +pub enum LLVMResult { + OK, + ALLOCATE_FAILURE, + PROTECT_FAILURE, + DEALLOC_FAILURE, + OBJECT_LOAD_FAILURE, +} + +#[repr(C)] +pub struct Callbacks { + pub alloc_memory: extern "C" fn(usize, MemProtect, &mut *mut u8, &mut usize) -> LLVMResult, + pub protect_memory: extern "C" fn(*mut u8, usize, MemProtect) -> LLVMResult, + pub dealloc_memory: extern "C" fn(*mut u8, usize) -> LLVMResult, + + pub lookup_vm_symbol: extern "C" fn(*const c_char, usize) -> *const vm::Func, + pub visit_fde: extern "C" fn(*mut u8, usize, extern "C" fn(*mut u8)), +} diff --git a/lib/runtime/Cargo.toml b/lib/runtime/Cargo.toml index e8e02afd01e..b4ac5c9d5a3 100644 --- a/lib/runtime/Cargo.toml +++ b/lib/runtime/Cargo.toml @@ -27,7 +27,7 @@ tempfile = "3.0.7" criterion = "0.2" wabt = "0.9.0" -[target.'cfg(not(windows))'.dependencies.wasmer-llvm-backend] +[dependencies.wasmer-llvm-backend] path = "../llvm-backend" optional = true From 89178732cc223bd0f30eceacfa27e0d313ba8f38 Mon Sep 17 00:00:00 2001 From: Syrus Date: Tue, 30 Jul 2019 15:23:03 -0700 Subject: [PATCH 2/6] Fixed unix errors --- lib/llvm-backend/src/platform/unix.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/llvm-backend/src/platform/unix.rs b/lib/llvm-backend/src/platform/unix.rs index 61e8af76a96..051869fdda1 100644 --- a/lib/llvm-backend/src/platform/unix.rs +++ b/lib/llvm-backend/src/platform/unix.rs @@ -1,11 +1,11 @@ use super::common::round_up_to_page_size; use crate::structs::{LLVMResult, MemProtect}; use libc::{ - c_char, mmap, mprotect, munmap, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_NONE, PROT_READ, - PROT_WRITE, + mmap, mprotect, munmap, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_NONE, PROT_READ, + PROT_WRITE, c_void, siginfo_t }; -use libc::{c_void, siginfo_t}; use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, SIGBUS, SIGSEGV}; +use std::ptr; /// `__register_frame` and `__deregister_frame` on macos take a single fde as an /// argument, so we need to parse the fde table here. From 22f8b3f3dc61c7767bd58a3a65481318f9abbfdc Mon Sep 17 00:00:00 2001 From: Syrus Date: Tue, 30 Jul 2019 15:32:21 -0700 Subject: [PATCH 3/6] Improved LLVM compilation for Unix --- lib/llvm-backend/cpp/object_loader.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/llvm-backend/cpp/object_loader.cpp b/lib/llvm-backend/cpp/object_loader.cpp index 3ec3f5d1a7f..5323505781c 100644 --- a/lib/llvm-backend/cpp/object_loader.cpp +++ b/lib/llvm-backend/cpp/object_loader.cpp @@ -75,16 +75,24 @@ struct MemoryManager : llvm::RuntimeDyld::MemoryManager { } virtual void registerEHFrames(uint8_t* addr, uint64_t LoadAddr, size_t size) override { - /* eh_frame_ptr = addr; + // We don't know yet how to do this on Windows, so we hide this on compilation + // so we can compile and pass spectests on unix systems + #ifndef _WIN32 + eh_frame_ptr = addr; eh_frame_size = size; eh_frames_registered = true; - callbacks.visit_fde(addr, size, __register_frame);*/ + callbacks.visit_fde(addr, size, __register_frame); + #endif } virtual void deregisterEHFrames() override { - /* if (eh_frames_registered) { + // We don't know yet how to do this on Windows, so we hide this on compilation + // so we can compile and pass spectests on unix systems + #ifndef _WIN32 + if (eh_frames_registered) { callbacks.visit_fde(eh_frame_ptr, eh_frame_size, __deregister_frame); - }*/ + } + #endif } virtual bool finalizeMemory(std::string *ErrMsg = nullptr) override { From 97c6956d98f9ad8bc6b7480bb8ae670b669407bf Mon Sep 17 00:00:00 2001 From: Syrus Date: Tue, 30 Jul 2019 15:56:25 -0700 Subject: [PATCH 4/6] Added llvm in windows support to Changelog --- CHANGELOG.md | 1 + lib/llvm-backend/src/platform/unix.rs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb9af14879c..1eda567aeef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All PRs to the Wasmer repository must add to this file. Blocks of changes will separated by version increments. ## **[Unreleased]** +- [#598](https://github.com/wasmerio/wasmer/pull/598) LLVM Backend is now supported in Windows - [#579](https://github.com/wasmerio/wasmer/pull/579) Fix bug in caching with LLVM and Singlepass backends. Add `default-backend-singlepass`, `default-backend-llvm`, and `default-backend-cranelift` features to `wasmer-runtime` to control the `default_compiler()` function (this is a breaking change). Add `compiler_for_backend` function in `wasmer-runtime` diff --git a/lib/llvm-backend/src/platform/unix.rs b/lib/llvm-backend/src/platform/unix.rs index 051869fdda1..a07afa13042 100644 --- a/lib/llvm-backend/src/platform/unix.rs +++ b/lib/llvm-backend/src/platform/unix.rs @@ -1,8 +1,8 @@ use super::common::round_up_to_page_size; use crate::structs::{LLVMResult, MemProtect}; use libc::{ - mmap, mprotect, munmap, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_NONE, PROT_READ, - PROT_WRITE, c_void, siginfo_t + c_void, mmap, mprotect, munmap, siginfo_t, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_NONE, + PROT_READ, PROT_WRITE, }; use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, SIGBUS, SIGSEGV}; use std::ptr; From 1d0ac80fa8562183628a744e257e7868f1466834 Mon Sep 17 00:00:00 2001 From: Syrus Date: Tue, 30 Jul 2019 15:56:42 -0700 Subject: [PATCH 5/6] Improved Appveyor build times --- .appveyor.yml | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 408f98a21af..8aaf485d69d 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -18,7 +18,6 @@ environment: cache: - 'C:\Users\appveyor\.cargo' - target - - wapm-cli-target install: # Install LLVM @@ -51,16 +50,7 @@ build_script: - cargo build --release --verbose - git submodule init - git submodule update - # Cache wapm cli target in dir above to prevent breaking git submodule on windows - - if not exist wapm-cli-target mkdir wapm-cli-target - - move wapm-cli-target wapm-cli - - cd wapm-cli - - rename wapm-cli-target target - - cd .. - - cargo build --release --manifest-path wapm-cli/Cargo.toml --features "telemetry update-notifications" - - cd wapm-cli - - cd .. - - xcopy wapm-cli\target wapm-cli-target\ /i /y + - if %APPVEYOR_REPO_BRANCH%==master cargo build --release --manifest-path wapm-cli/Cargo.toml --features "telemetry update-notifications" - cargo build --release --manifest-path lib/runtime-c-api/Cargo.toml test_script: From 020b94836cefb9c2e55d4f8f95866d8f201d19c3 Mon Sep 17 00:00:00 2001 From: Syrus Date: Tue, 30 Jul 2019 17:02:16 -0700 Subject: [PATCH 6/6] Added more examples into the repo --- examples/particle-repel-simd.wasm | Bin 0 -> 353392 bytes examples/particle-repel.wasm | Bin 0 -> 353498 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100755 examples/particle-repel-simd.wasm create mode 100755 examples/particle-repel.wasm diff --git a/examples/particle-repel-simd.wasm b/examples/particle-repel-simd.wasm new file mode 100755 index 0000000000000000000000000000000000000000..ecc781c450c1979162d5015fd87ff427bafc16fd GIT binary patch literal 353392 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 Te^22N7|NydZ_cB?uWtMw`X-n! literal 0 HcmV?d00001 diff --git a/examples/particle-repel.wasm b/examples/particle-repel.wasm new file mode 100755 index 0000000000000000000000000000000000000000..7acadf73a6c44e847a748387f8780f380a870b96 GIT binary patch literal 353498 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