From 34b5e44eb9c3a1974902dd2606e03f5554f32dfc Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 10 Jun 2019 13:33:51 +0200 Subject: [PATCH 01/90] add beginnings of debugging document --- docs/debugging.md | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 docs/debugging.md diff --git a/docs/debugging.md b/docs/debugging.md new file mode 100644 index 00000000000..8d49d52175b --- /dev/null +++ b/docs/debugging.md @@ -0,0 +1,50 @@ +# Debugging Wasmer + +## When is this document useful? + +If you're developing wasmer or running into issues, this document will explain to useful techniques and common errors. + +## Tracing syscalls + +To trace syscalls, compile with the `debug` feature (`cargo build --features "debug"`). For even more verbose messages, use the `trace` flag. + +## Tracing calls + +TODO: did we disable tracing calls? if not talk about how to enable it +TODO: someone with more context on the backends mention which backends this works for + +If you'd like to see all calls and you're using emscripten, you can use a symbol map to get better error output with the `em-symbol-map` flag. + +## Common things that can go wrong + +### Missing imports + +If, when attempting to run a wasm module, you get an error about missing imports there are a number of things that could be going wrong. + +The most likely is that we haven't implemented those imports for your ABI. If you're targeting emscripten, this is probably the issue. + +However if that's not the case, then there's a chance that you're using an unsupported ABI (let us know!) or that the wasm is invalid for the detected ABI. (TODO: link to wasm contracts or something) + +### Hitting `undefined` + +If this happens it's because wasmer does not have full support for whatever feature you tried to use. Running with tracing on can help clarify the issue if it's not clear from the message. + +To fix this, file an issue letting us know that wasmer is missing a feature that's important to you. If you'd like, you can try to implement it yourself and send us a PR. + +### No output + +If you're seeing no output from running the wasm module then it may be that: +- this is the intended behavior of the wasm module +- or it's very slow to compile (try compiling with a faster backend like cranelift (the default) or singlepass (requires nightly)) + +### Segfault + +If you're seeing a segfault while developing wasmer, chances are that it's a cache issue. We reset the cache on every version bump, but if you're running it from source then the cache may become invalid, which can lead to segfaults. + +To fix this delete the cache with `wasmer cache clean` or run the command with the `disable-cache` flag (`wasmer run some.wasm --disable-cache`) + +If you're seeing a segfault with a released version of wasmer, please file an issue so we can ship an updated version as soon as possible. + +### Something else + +If none of this has helped with your issue, let us know and we'll do our best to help. From a14a8e4c5052d937371417889ccff234314c275a Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 18 Jul 2019 02:43:04 +0800 Subject: [PATCH 02/90] Emit stack map at critical points. --- lib/llvm-backend/src/code.rs | 124 ++++++++++++++++++++++++++++- lib/llvm-backend/src/intrinsics.rs | 13 +++ lib/llvm-backend/src/state.rs | 2 +- 3 files changed, 135 insertions(+), 4 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 2eb8d441e53..18b94c89267 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -8,6 +8,8 @@ use inkwell::{ AddressSpace, FloatPredicate, IntPredicate, }; use smallvec::SmallVec; +use std::cell::RefCell; +use std::rc::Rc; use std::sync::{Arc, RwLock}; use wasmer_runtime_core::{ backend::{Backend, CacheGen, Token}, @@ -299,11 +301,67 @@ fn resolve_memory_ptr( Ok(builder.build_int_to_ptr(effective_address_int, ptr_ty, &state.var_name())) } +fn emit_stack_map( + intrinsics: &Intrinsics, + builder: &Builder, + local_function_id: usize, + target: &mut StackmapRegistry, + kind: StackmapEntryKind, + locals: &[PointerValue], + state: &State, +) { + let stackmap_id = target.entries.len(); + + let mut params = vec![]; + + params.push( + intrinsics + .i64_ty + .const_int(stackmap_id as u64, false) + .as_basic_value_enum(), + ); + params.push(intrinsics.i32_ty.const_int(0, false).as_basic_value_enum()); + + let locals: Vec<_> = locals.iter().map(|x| x.as_basic_value_enum()).collect(); + + params.extend_from_slice(&locals); + params.extend_from_slice(&state.stack); + + builder.build_call(intrinsics.experimental_stackmap, ¶ms, &state.var_name()); + + target.entries.push(StackmapEntry { + kind, + local_function_id, + local_count: locals.len(), + stack_count: state.stack.len(), + }); +} + #[derive(Debug)] pub struct CodegenError { pub message: String, } +#[derive(Default, Debug, Clone)] +pub struct StackmapRegistry { + entries: Vec, +} + +#[derive(Debug, Clone)] +pub struct StackmapEntry { + kind: StackmapEntryKind, + local_function_id: usize, + local_count: usize, + stack_count: usize, +} + +#[derive(Debug, Clone, Copy)] +pub enum StackmapEntryKind { + Loop, + Call, + Trappable, +} + pub struct LLVMModuleCodeGenerator { context: Option, builder: Option, @@ -315,6 +373,7 @@ pub struct LLVMModuleCodeGenerator { func_import_count: usize, personality_func: FunctionValue, module: Module, + stackmaps: Rc>, } pub struct LLVMFunctionCodeGenerator { @@ -329,6 +388,8 @@ pub struct LLVMFunctionCodeGenerator { num_params: usize, ctx: Option>, unreachable_depth: usize, + stackmaps: Rc>, + index: usize, } impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { @@ -487,6 +548,20 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { }; builder.position_at_end(&loop_body); + + { + let mut stackmaps = self.stackmaps.borrow_mut(); + emit_stack_map( + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Loop, + &self.locals, + state, + ) + } + state.push_loop(loop_body, loop_next, phis); } Operator::Br { relative_depth } => { @@ -748,6 +823,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { // If llvm cannot prove that this is never touched, // it will emit a `ud2` instruction on x86_64 arches. + { + let mut stackmaps = self.stackmaps.borrow_mut(); + emit_stack_map( + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Trappable, + &self.locals, + state, + ) + } + builder.build_call( intrinsics.throw_trap, &[intrinsics.trap_unreachable], @@ -850,7 +938,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let llvm_sig = signatures[sigindex]; let func_sig = &info.signatures[sigindex]; - let call_site = match func_index.local_or_import(info) { + let (params, func_ptr) = match func_index.local_or_import(info) { LocalOrImport::Local(local_func_index) => { let params: Vec<_> = [ctx.basic()] .iter() @@ -861,7 +949,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let func_ptr = ctx.local_func(local_func_index, llvm_sig, intrinsics, builder); - builder.build_call(func_ptr, ¶ms, &state.var_name()) + (params, func_ptr) } LocalOrImport::Import(import_func_index) => { let (func_ptr_untyped, ctx_ptr) = @@ -880,11 +968,24 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { "typed_func_ptr", ); - builder.build_call(func_ptr, ¶ms, &state.var_name()) + (params, func_ptr) } }; state.popn(func_sig.params().len())?; + { + let mut stackmaps = self.stackmaps.borrow_mut(); + emit_stack_map( + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Call, + &self.locals, + state, + ) + } + let call_site = builder.build_call(func_ptr, ¶ms, &state.var_name()); if let Some(basic_value) = call_site.try_as_basic_value().left() { match func_sig.returns().len() { @@ -1049,6 +1150,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { "typed_func_ptr", ); + { + let mut stackmaps = self.stackmaps.borrow_mut(); + emit_stack_map( + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Call, + &self.locals, + state, + ) + } let call_site = builder.build_call(typed_func_ptr, &args, "indirect_call"); match wasmer_fn_sig.returns() { @@ -2396,6 +2509,7 @@ impl ModuleCodeGenerator function_signatures: None, func_import_count: 0, personality_func, + stackmaps: Rc::new(RefCell::new(StackmapRegistry::default())), } } @@ -2468,6 +2582,8 @@ impl ModuleCodeGenerator ); let num_params = locals.len(); + let local_func_index = self.functions.len(); + let code = LLVMFunctionCodeGenerator { state, context: Some(context), @@ -2480,6 +2596,8 @@ impl ModuleCodeGenerator num_params, ctx: None, unreachable_depth: 0, + stackmaps: self.stackmaps.clone(), + index: local_func_index, }; self.functions.push(code); Ok(self.functions.last_mut().unwrap()) diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index c3a95f7751a..41526ee646d 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -115,6 +115,8 @@ pub struct Intrinsics { pub throw_trap: FunctionValue, + pub experimental_stackmap: FunctionValue, + pub ctx_ptr_ty: PointerType, } @@ -391,6 +393,17 @@ impl Intrinsics { void_ty.fn_type(&[i32_ty_basic], false), None, ), + experimental_stackmap: module.add_function( + "llvm.experimental.stackmap", + void_ty.fn_type( + &[ + i64_ty_basic, /* id */ + i32_ty_basic, /* numShadowBytes */ + ], + true, + ), + None, + ), ctx_ptr_ty, } } diff --git a/lib/llvm-backend/src/state.rs b/lib/llvm-backend/src/state.rs index 47da54a6d79..20f915ebce7 100644 --- a/lib/llvm-backend/src/state.rs +++ b/lib/llvm-backend/src/state.rs @@ -69,7 +69,7 @@ impl ControlFrame { #[derive(Debug)] pub struct State { - stack: Vec, + pub stack: Vec, control_stack: Vec, value_counter: Cell, From 2e030c9c4a2ab144bae929d8e3e4c395cbcc89ef Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 19 Jul 2019 02:02:15 +0800 Subject: [PATCH 03/90] Parsing LLVM stackmaps. --- lib/llvm-backend/Cargo.toml | 1 + lib/llvm-backend/cpp/object_loader.cpp | 60 ++++++- lib/llvm-backend/cpp/object_loader.hh | 22 ++- lib/llvm-backend/src/backend.rs | 41 ++++- lib/llvm-backend/src/code.rs | 26 +--- lib/llvm-backend/src/lib.rs | 1 + lib/llvm-backend/src/stackmap.rs | 208 +++++++++++++++++++++++++ 7 files changed, 333 insertions(+), 26 deletions(-) create mode 100644 lib/llvm-backend/src/stackmap.rs diff --git a/lib/llvm-backend/Cargo.toml b/lib/llvm-backend/Cargo.toml index e5e93261b3e..37c8edbca8f 100644 --- a/lib/llvm-backend/Cargo.toml +++ b/lib/llvm-backend/Cargo.toml @@ -14,6 +14,7 @@ goblin = "0.0.20" libc = "0.2.49" nix = "0.14.0" capstone = { version = "0.5.0", optional = true } +byteorder = "1" [build-dependencies] cc = "1.0" diff --git a/lib/llvm-backend/cpp/object_loader.cpp b/lib/llvm-backend/cpp/object_loader.cpp index 28bea635494..bb7f0288450 100644 --- a/lib/llvm-backend/cpp/object_loader.cpp +++ b/lib/llvm-backend/cpp/object_loader.cpp @@ -9,6 +9,22 @@ struct MemoryManager : llvm::RuntimeDyld::MemoryManager { public: MemoryManager(callbacks_t callbacks) : callbacks(callbacks) {} + uint8_t * get_stack_map_ptr() const { + return stack_map_ptr; + } + + size_t get_stack_map_size() const { + return stack_map_size; + } + + uint8_t * get_code_ptr() const { + return (uint8_t *) code_start_ptr; + } + + size_t get_code_size() const { + return code_size; + } + virtual ~MemoryManager() override { deregisterEHFrames(); // Deallocate all of the allocated memory. @@ -24,11 +40,17 @@ struct MemoryManager : llvm::RuntimeDyld::MemoryManager { virtual uint8_t* allocateDataSection(uintptr_t size, unsigned alignment, unsigned section_id, llvm::StringRef section_name, bool read_only) override { // Allocate from the read-only section or the read-write section, depending on if this allocation // should be read-only or not. + uint8_t *ret; if (read_only) { - return allocate_bump(read_section, read_bump_ptr, size, alignment); + ret = allocate_bump(read_section, read_bump_ptr, size, alignment); } else { - return allocate_bump(readwrite_section, readwrite_bump_ptr, size, alignment); + ret = allocate_bump(readwrite_section, readwrite_bump_ptr, size, alignment); } + if(section_name.equals(llvm::StringRef("__llvm_stackmaps")) || section_name.equals(llvm::StringRef(".llvm_stackmaps"))) { + stack_map_ptr = ret; + stack_map_size = size; + } + return ret; } virtual void reserveAllocationSpace( @@ -53,6 +75,8 @@ struct MemoryManager : llvm::RuntimeDyld::MemoryManager { assert(code_result == RESULT_OK); code_section = Section { code_ptr_out, code_size_out }; code_bump_ptr = (uintptr_t)code_ptr_out; + code_start_ptr = (uintptr_t)code_ptr_out; + this->code_size = code_size; uint8_t *read_ptr_out = nullptr; size_t read_size_out = 0; @@ -127,12 +151,17 @@ struct MemoryManager : llvm::RuntimeDyld::MemoryManager { } Section code_section, read_section, readwrite_section; + uintptr_t code_start_ptr; + size_t code_size; uintptr_t code_bump_ptr, read_bump_ptr, readwrite_bump_ptr; uint8_t* eh_frame_ptr; size_t eh_frame_size; bool eh_frames_registered = false; callbacks_t callbacks; + + uint8_t *stack_map_ptr = nullptr; + size_t stack_map_size = 0; }; struct SymbolLookup : llvm::JITSymbolResolver { @@ -201,4 +230,29 @@ WasmModule::WasmModule( void* WasmModule::get_func(llvm::StringRef name) const { auto symbol = runtime_dyld->getSymbol(name); return (void*)symbol.getAddress(); -} \ No newline at end of file +} + +uint8_t * WasmModule::get_stack_map_ptr() const { + llvm::RuntimeDyld::MemoryManager& mm = *memory_manager; + MemoryManager *local_mm = dynamic_cast(&mm); + return local_mm->get_stack_map_ptr(); +} + +size_t WasmModule::get_stack_map_size() const { + llvm::RuntimeDyld::MemoryManager& mm = *memory_manager; + MemoryManager *local_mm = dynamic_cast(&mm); + return local_mm->get_stack_map_size(); +} + + +uint8_t * WasmModule::get_code_ptr() const { + llvm::RuntimeDyld::MemoryManager& mm = *memory_manager; + MemoryManager *local_mm = dynamic_cast(&mm); + return local_mm->get_code_ptr(); +} + +size_t WasmModule::get_code_size() const { + llvm::RuntimeDyld::MemoryManager& mm = *memory_manager; + MemoryManager *local_mm = dynamic_cast(&mm); + return local_mm->get_code_size(); +} diff --git a/lib/llvm-backend/cpp/object_loader.hh b/lib/llvm-backend/cpp/object_loader.hh index 63630a479b1..146f9cd337d 100644 --- a/lib/llvm-backend/cpp/object_loader.hh +++ b/lib/llvm-backend/cpp/object_loader.hh @@ -156,6 +156,10 @@ struct WasmModule callbacks_t callbacks); void *get_func(llvm::StringRef name) const; + uint8_t *get_stack_map_ptr() const; + size_t get_stack_map_size() const; + uint8_t *get_code_ptr() const; + size_t get_code_size() const; bool _init_failed = false; private: @@ -233,4 +237,20 @@ extern "C" { return module->get_func(llvm::StringRef(name)); } -} \ No newline at end of file + + const uint8_t *llvm_backend_get_stack_map_ptr(const WasmModule *module) { + return module->get_stack_map_ptr(); + } + + size_t llvm_backend_get_stack_map_size(const WasmModule *module) { + return module->get_stack_map_size(); + } + + const uint8_t *llvm_backend_get_code_ptr(const WasmModule *module) { + return module->get_code_ptr(); + } + + size_t llvm_backend_get_code_size(const WasmModule *module) { + return module->get_code_size(); + } +} diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index 7a8c6c64ac8..fd849f00f6d 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -1,3 +1,4 @@ +use super::stackmap::{self, StackmapRegistry}; use crate::intrinsics::Intrinsics; use inkwell::{ memory_buffer::MemoryBuffer, @@ -25,6 +26,7 @@ use wasmer_runtime_core::{ }, cache::Error as CacheError, module::ModuleInfo, + state::ModuleStateMap, structures::TypedIndex, typed_func::{Wasm, WasmTrapInfo}, types::{LocalFuncIndex, SigIndex}, @@ -76,6 +78,10 @@ extern "C" { ) -> LLVMResult; fn module_delete(module: *mut LLVMModule); fn get_func_symbol(module: *mut LLVMModule, name: *const c_char) -> *const vm::Func; + fn llvm_backend_get_stack_map_ptr(module: *const LLVMModule) -> *const u8; + fn llvm_backend_get_stack_map_size(module: *const LLVMModule) -> usize; + fn llvm_backend_get_code_ptr(module: *const LLVMModule) -> *const u8; + fn llvm_backend_get_code_size(module: *const LLVMModule) -> usize; fn throw_trap(ty: i32); @@ -231,10 +237,15 @@ pub struct LLVMBackend { module: *mut LLVMModule, #[allow(dead_code)] buffer: Arc, + msm: Option, } impl LLVMBackend { - pub fn new(module: Module, _intrinsics: Intrinsics) -> (Self, LLVMCache) { + pub fn new( + module: Module, + _intrinsics: Intrinsics, + _stackmaps: &StackmapRegistry, + ) -> (Self, LLVMCache) { Target::initialize_x86(&InitializationConfig { asm_parser: true, asm_printer: true, @@ -285,10 +296,24 @@ impl LLVMBackend { let buffer = Arc::new(Buffer::LlvmMemory(memory_buffer)); + let raw_stackmap = unsafe { + ::std::slice::from_raw_parts( + llvm_backend_get_stack_map_ptr(module), + llvm_backend_get_stack_map_size(module), + ) + }; + if raw_stackmap.len() > 0 { + let map = stackmap::StackMap::parse(raw_stackmap); + eprintln!("{:?}", map); + } else { + eprintln!("WARNING: No stack map"); + } + ( Self { module, buffer: Arc::clone(&buffer), + msm: None, }, LLVMCache { buffer }, ) @@ -318,6 +343,7 @@ impl LLVMBackend { Self { module, buffer: Arc::clone(&buffer), + msm: None, }, LLVMCache { buffer }, )) @@ -372,6 +398,19 @@ impl RunnableModule for LLVMBackend { Some(unsafe { Wasm::from_raw_parts(trampoline, invoke_trampoline, None) }) } + fn get_code(&self) -> Option<&[u8]> { + Some(unsafe { + ::std::slice::from_raw_parts( + llvm_backend_get_code_ptr(self.module), + llvm_backend_get_code_size(self.module), + ) + }) + } + + fn get_module_state_map(&self) -> Option { + self.msm.clone() + } + 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 18b94c89267..e5f52df75b7 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -27,6 +27,7 @@ use wasmparser::{BinaryReaderError, MemoryImmediate, Operator, Type as WpType}; use crate::backend::LLVMBackend; use crate::intrinsics::{CtxType, GlobalCache, Intrinsics, MemoryCache}; use crate::read_info::{blocktype_to_type, type_to_type}; +use crate::stackmap::{StackmapEntry, StackmapEntryKind, StackmapRegistry}; use crate::state::{ControlFrame, IfElseState, State}; use crate::trampolines::generate_trampolines; @@ -342,26 +343,6 @@ pub struct CodegenError { pub message: String, } -#[derive(Default, Debug, Clone)] -pub struct StackmapRegistry { - entries: Vec, -} - -#[derive(Debug, Clone)] -pub struct StackmapEntry { - kind: StackmapEntryKind, - local_function_id: usize, - local_count: usize, - stack_count: usize, -} - -#[derive(Debug, Clone, Copy)] -pub enum StackmapEntryKind { - Loop, - Call, - Trappable, -} - pub struct LLVMModuleCodeGenerator { context: Option, builder: Option, @@ -2653,7 +2634,10 @@ impl ModuleCodeGenerator // self.module.print_to_stderr(); - let (backend, cache_gen) = LLVMBackend::new(self.module, self.intrinsics.take().unwrap()); + let stackmaps = self.stackmaps.borrow(); + + let (backend, cache_gen) = + LLVMBackend::new(self.module, self.intrinsics.take().unwrap(), &*stackmaps); Ok((backend, Box::new(cache_gen))) } diff --git a/lib/llvm-backend/src/lib.rs b/lib/llvm-backend/src/lib.rs index 6d8816af8a3..d6a810fbe3f 100644 --- a/lib/llvm-backend/src/lib.rs +++ b/lib/llvm-backend/src/lib.rs @@ -6,6 +6,7 @@ mod code; mod intrinsics; mod platform; mod read_info; +mod stackmap; mod state; mod trampolines; diff --git a/lib/llvm-backend/src/stackmap.rs b/lib/llvm-backend/src/stackmap.rs new file mode 100644 index 00000000000..762d46c6845 --- /dev/null +++ b/lib/llvm-backend/src/stackmap.rs @@ -0,0 +1,208 @@ +// https://llvm.org/docs/StackMaps.html#stackmap-section + +use byteorder::{LittleEndian, ReadBytesExt}; +use std::io::{self, Cursor}; + +#[derive(Default, Debug, Clone)] +pub struct StackmapRegistry { + pub entries: Vec, +} + +#[derive(Debug, Clone)] +pub struct StackmapEntry { + pub kind: StackmapEntryKind, + pub local_function_id: usize, + pub local_count: usize, + pub stack_count: usize, +} + +#[derive(Debug, Clone, Copy)] +pub enum StackmapEntryKind { + Loop, + Call, + Trappable, +} + +#[derive(Clone, Debug, Default)] +pub struct StackMap { + pub version: u8, + pub stk_size_records: Vec, + pub constants: Vec, + pub stk_map_records: Vec, +} + +#[derive(Copy, Clone, Debug, Default)] +pub struct StkSizeRecord { + pub function_address: u64, + pub stack_size: u64, + pub record_count: u64, +} + +#[derive(Copy, Clone, Debug, Default)] +pub struct Constant { + pub large_constant: u64, +} + +#[derive(Clone, Debug, Default)] +pub struct StkMapRecord { + pub patchpoint_id: u64, + pub instruction_offset: u32, + pub locations: Vec, + pub live_outs: Vec, +} + +#[derive(Copy, Clone, Debug)] +pub struct Location { + pub ty: LocationType, + pub location_size: u16, + pub dwarf_regnum: u16, + pub offset_or_small_constant: i32, +} + +#[derive(Copy, Clone, Debug, Default)] +pub struct LiveOut { + pub dwarf_regnum: u16, + pub size_in_bytes: u8, +} + +#[derive(Copy, Clone, Debug)] +pub enum LocationType { + Register, + Direct, + Indirect, + Constant, + ConstantIndex, +} + +impl StackMap { + pub fn parse(raw: &[u8]) -> io::Result { + let mut reader = Cursor::new(raw); + let mut map = StackMap::default(); + + let version = reader.read_u8()?; + if version != 3 { + return Err(io::Error::new(io::ErrorKind::Other, "version is not 3")); + } + map.version = version; + if reader.read_u8()? != 0 { + return Err(io::Error::new( + io::ErrorKind::Other, + "reserved field is not zero (1)", + )); + } + if reader.read_u16::()? != 0 { + return Err(io::Error::new( + io::ErrorKind::Other, + "reserved field is not zero (2)", + )); + } + let num_functions = reader.read_u32::()?; + let num_constants = reader.read_u32::()?; + let num_records = reader.read_u32::()?; + for _ in 0..num_functions { + let mut record = StkSizeRecord::default(); + record.function_address = reader.read_u64::()?; + record.stack_size = reader.read_u64::()?; + record.record_count = reader.read_u64::()?; + map.stk_size_records.push(record); + } + for _ in 0..num_constants { + map.constants.push(Constant { + large_constant: reader.read_u64::()?, + }); + } + for _ in 0..num_records { + let mut record = StkMapRecord::default(); + + record.patchpoint_id = reader.read_u64::()?; + record.instruction_offset = reader.read_u32::()?; + if reader.read_u16::()? != 0 { + return Err(io::Error::new( + io::ErrorKind::Other, + "reserved field is not zero (3)", + )); + } + let num_locations = reader.read_u16::()?; + for _ in 0..num_locations { + let ty = reader.read_u8()?; + + let mut location = Location { + ty: match ty { + 1 => LocationType::Register, + 2 => LocationType::Direct, + 3 => LocationType::Indirect, + 4 => LocationType::Constant, + 5 => LocationType::ConstantIndex, + _ => { + return Err(io::Error::new( + io::ErrorKind::Other, + "unknown location type", + )) + } + }, + location_size: 0, + dwarf_regnum: 0, + offset_or_small_constant: 0, + }; + + if reader.read_u8()? != 0 { + return Err(io::Error::new( + io::ErrorKind::Other, + "reserved field is not zero (4)", + )); + } + location.location_size = reader.read_u16::()?; + location.dwarf_regnum = reader.read_u16::()?; + if reader.read_u16::()? != 0 { + return Err(io::Error::new( + io::ErrorKind::Other, + "reserved field is not zero (5)", + )); + } + location.offset_or_small_constant = reader.read_i32::()?; + + record.locations.push(location); + } + if reader.position() % 8 != 0 { + if reader.read_u32::()? != 0 { + return Err(io::Error::new( + io::ErrorKind::Other, + "reserved field is not zero (6)", + )); + } + } + if reader.read_u16::()? != 0 { + return Err(io::Error::new( + io::ErrorKind::Other, + "reserved field is not zero (7)", + )); + } + let num_live_outs = reader.read_u16::()?; + for _ in 0..num_live_outs { + let mut liveout = LiveOut::default(); + + liveout.dwarf_regnum = reader.read_u16::()?; + if reader.read_u8()? != 0 { + return Err(io::Error::new( + io::ErrorKind::Other, + "reserved field is not zero (8)", + )); + } + liveout.size_in_bytes = reader.read_u8()?; + + record.live_outs.push(liveout); + } + if reader.position() % 8 != 0 { + if reader.read_u32::()? != 0 { + return Err(io::Error::new( + io::ErrorKind::Other, + "reserved field is not zero (9)", + )); + } + } + + map.stk_map_records.push(record); + } + Ok(map) + } +} From 0133b92bec2475f773f49841c59bb4297c31ccd3 Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 23 Jul 2019 02:55:43 +0800 Subject: [PATCH 04/90] Populating LLVM stack maps into MSM/FSM. --- Cargo.lock | 1 + lib/llvm-backend/src/backend.rs | 32 ++++- lib/llvm-backend/src/code.rs | 44 ++++++- lib/llvm-backend/src/stackmap.rs | 220 +++++++++++++++++++++++++++++++ lib/runtime-core/src/state.rs | 32 +++++ 5 files changed, 321 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index df886045920..efed2e60c30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1495,6 +1495,7 @@ dependencies = [ name = "wasmer-llvm-backend" version = "0.5.6" dependencies = [ + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "capstone 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.20 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index fd849f00f6d..778f7ddbad2 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -244,7 +244,7 @@ impl LLVMBackend { pub fn new( module: Module, _intrinsics: Intrinsics, - _stackmaps: &StackmapRegistry, + stackmaps: &StackmapRegistry, ) -> (Self, LLVMCache) { Target::initialize_x86(&InitializationConfig { asm_parser: true, @@ -303,8 +303,36 @@ impl LLVMBackend { ) }; if raw_stackmap.len() > 0 { - let map = stackmap::StackMap::parse(raw_stackmap); + let map = stackmap::StackMap::parse(raw_stackmap).unwrap(); eprintln!("{:?}", map); + + let (code_ptr, code_size) = unsafe { + ( + llvm_backend_get_code_ptr(module), + llvm_backend_get_code_size(module), + ) + }; + let mut msm = ModuleStateMap { + local_functions: Default::default(), + total_size: code_size, + }; + let mut map_record_idx: usize = 0; + for size_record in &map.stk_size_records { + for _ in 0..size_record.record_count { + let map_record = &map.stk_map_records[map_record_idx]; + let map_entry = &stackmaps.entries[map_record_idx]; + assert_eq!(map_record.patchpoint_id, map_record_idx as u64); + map_record_idx += 1; + + map_entry.populate_msm( + code_ptr as usize, + &map, + size_record, + map_record, + &mut msm, + ); + } + } } else { eprintln!("WARNING: No stack map"); } diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index e5f52df75b7..32131873fd7 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -27,7 +27,7 @@ use wasmparser::{BinaryReaderError, MemoryImmediate, Operator, Type as WpType}; use crate::backend::LLVMBackend; use crate::intrinsics::{CtxType, GlobalCache, Intrinsics, MemoryCache}; use crate::read_info::{blocktype_to_type, type_to_type}; -use crate::stackmap::{StackmapEntry, StackmapEntryKind, StackmapRegistry}; +use crate::stackmap::{StackmapEntry, StackmapEntryKind, StackmapRegistry, ValueSemantic}; use crate::state::{ControlFrame, IfElseState, State}; use crate::trampolines::generate_trampolines; @@ -310,6 +310,7 @@ fn emit_stack_map( kind: StackmapEntryKind, locals: &[PointerValue], state: &State, + opcode_offset: usize, ) { let stackmap_id = target.entries.len(); @@ -324,9 +325,13 @@ fn emit_stack_map( params.push(intrinsics.i32_ty.const_int(0, false).as_basic_value_enum()); let locals: Vec<_> = locals.iter().map(|x| x.as_basic_value_enum()).collect(); + let mut value_semantics: Vec = vec![]; params.extend_from_slice(&locals); + value_semantics.extend((0..locals.len()).map(ValueSemantic::WasmLocal)); + params.extend_from_slice(&state.stack); + value_semantics.extend((0..state.stack.len()).map(ValueSemantic::WasmStack)); builder.build_call(intrinsics.experimental_stackmap, ¶ms, &state.var_name()); @@ -335,6 +340,8 @@ fn emit_stack_map( local_function_id, local_count: locals.len(), stack_count: state.stack.len(), + opcode_offset, + value_semantics, }); } @@ -371,6 +378,7 @@ pub struct LLVMFunctionCodeGenerator { unreachable_depth: usize, stackmaps: Rc>, index: usize, + opcode_offset: usize, } impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { @@ -443,8 +451,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } fn feed_event(&mut self, event: Event, module_info: &ModuleInfo) -> Result<(), CodegenError> { + let mut opcode_offset: Option = None; let op = match event { - Event::Wasm(x) => x, + Event::Wasm(x) => { + opcode_offset = Some(self.opcode_offset); + self.opcode_offset += 1; + x + } Event::Internal(_x) => { return Ok(()); } @@ -530,7 +543,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.position_at_end(&loop_body); - { + if let Some(offset) = opcode_offset { let mut stackmaps = self.stackmaps.borrow_mut(); emit_stack_map( intrinsics, @@ -540,6 +553,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { StackmapEntryKind::Loop, &self.locals, state, + offset, ) } @@ -804,7 +818,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { // If llvm cannot prove that this is never touched, // it will emit a `ud2` instruction on x86_64 arches. - { + if let Some(offset) = opcode_offset { let mut stackmaps = self.stackmaps.borrow_mut(); emit_stack_map( intrinsics, @@ -814,6 +828,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { StackmapEntryKind::Trappable, &self.locals, state, + offset, ) } @@ -954,7 +969,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { }; state.popn(func_sig.params().len())?; - { + if let Some(offset) = opcode_offset { let mut stackmaps = self.stackmaps.borrow_mut(); emit_stack_map( intrinsics, @@ -964,6 +979,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { StackmapEntryKind::Call, &self.locals, state, + offset, ) } let call_site = builder.build_call(func_ptr, ¶ms, &state.var_name()); @@ -1131,7 +1147,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { "typed_func_ptr", ); - { + if let Some(offset) = opcode_offset { let mut stackmaps = self.stackmaps.borrow_mut(); emit_stack_map( intrinsics, @@ -1141,6 +1157,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { StackmapEntryKind::Call, &self.locals, state, + offset, ) } let call_site = builder.build_call(typed_func_ptr, &args, "indirect_call"); @@ -2565,6 +2582,20 @@ impl ModuleCodeGenerator let local_func_index = self.functions.len(); + { + let mut stackmaps = self.stackmaps.borrow_mut(); + emit_stack_map( + &intrinsics, + &builder, + local_func_index, + &mut *stackmaps, + StackmapEntryKind::FunctionHeader, + &locals, + &state, + ::std::usize::MAX, + ); + } + let code = LLVMFunctionCodeGenerator { state, context: Some(context), @@ -2579,6 +2610,7 @@ impl ModuleCodeGenerator unreachable_depth: 0, stackmaps: self.stackmaps.clone(), index: local_func_index, + opcode_offset: 0, }; self.functions.push(code); Ok(self.functions.last_mut().unwrap()) diff --git a/lib/llvm-backend/src/stackmap.rs b/lib/llvm-backend/src/stackmap.rs index 762d46c6845..e75148f242e 100644 --- a/lib/llvm-backend/src/stackmap.rs +++ b/lib/llvm-backend/src/stackmap.rs @@ -1,7 +1,13 @@ // https://llvm.org/docs/StackMaps.html#stackmap-section use byteorder::{LittleEndian, ReadBytesExt}; +use std::collections::HashMap; use std::io::{self, Cursor}; +use wasmer_runtime_core::state::{ + x64::{new_machine_state, X64Register, GPR}, + FunctionStateMap, MachineStateDiff, MachineValue, ModuleStateMap, OffsetInfo, RegisterIndex, + SuspendOffset, WasmAbstractValue, +}; #[derive(Default, Debug, Clone)] pub struct StackmapRegistry { @@ -12,17 +18,231 @@ pub struct StackmapRegistry { pub struct StackmapEntry { pub kind: StackmapEntryKind, pub local_function_id: usize, + pub opcode_offset: usize, + pub value_semantics: Vec, pub local_count: usize, pub stack_count: usize, } +#[derive(Debug, Clone)] +pub enum ValueSemantic { + WasmLocal(usize), + WasmStack(usize), +} + #[derive(Debug, Clone, Copy)] pub enum StackmapEntryKind { + FunctionHeader, Loop, Call, Trappable, } +/* +pub struct FunctionStateMap { + pub initial: MachineState, + pub local_function_id: usize, + pub locals: Vec, + pub shadow_size: usize, // for single-pass backend, 32 bytes on x86-64 + pub diffs: Vec, + pub wasm_function_header_target_offset: Option, + pub wasm_offset_to_target_offset: BTreeMap, + pub loop_offsets: BTreeMap, /* suspend_offset -> info */ + pub call_offsets: BTreeMap, /* suspend_offset -> info */ + pub trappable_offsets: BTreeMap, /* suspend_offset -> info */ +} +pub struct MachineStateDiff { + pub last: Option, + pub stack_push: Vec, + pub stack_pop: usize, + pub reg_diff: Vec<(RegisterIndex, MachineValue)>, + + pub wasm_stack_push: Vec, + pub wasm_stack_pop: usize, + pub wasm_stack_private_depth: usize, // absolute value; not a diff. + + pub wasm_inst_offset: usize, // absolute value; not a diff. +} +*/ + +impl StackmapEntry { + pub fn populate_msm( + &self, + code_addr: usize, + llvm_map: &StackMap, + size_record: &StkSizeRecord, + map_record: &StkMapRecord, + msm: &mut ModuleStateMap, + ) { + #[derive(Copy, Clone, Debug)] + enum RuntimeOrConstant { + Runtime(MachineValue), + Constant(u64), + } + + let fsm = msm + .local_functions + .entry(self.local_function_id) + .or_insert_with(|| { + FunctionStateMap::new(new_machine_state(), self.local_function_id, 0, vec![]) + }); + + assert_eq!(self.value_semantics.len(), map_record.locations.len()); + assert!(size_record.stack_size % 8 == 0); + + let mut machine_stack_layout: Vec = + vec![MachineValue::Undefined; (size_record.stack_size as usize) / 8]; + let mut regs: Vec<(RegisterIndex, MachineValue)> = vec![]; + let mut stack_constants: HashMap = HashMap::new(); + + let mut wasm_locals: Vec = vec![]; + let mut wasm_stack: Vec = vec![]; + + for (i, loc) in map_record.locations.iter().enumerate() { + let mv = match self.value_semantics[i] { + ValueSemantic::WasmLocal(x) => { + if x != wasm_locals.len() { + panic!("unordered local values"); + } + wasm_locals.push(WasmAbstractValue::Runtime); + MachineValue::WasmLocal(x) + } + ValueSemantic::WasmStack(x) => { + if x != wasm_stack.len() { + panic!("unordered stack values"); + } + wasm_stack.push(WasmAbstractValue::Runtime); + MachineValue::WasmStack(x) + } + }; + match loc.ty { + LocationType::Register => { + let index = X64Register::from_dwarf_regnum(loc.dwarf_regnum) + .expect("invalid regnum") + .to_index(); + regs.push((index, mv)); + } + LocationType::Constant => { + let v = loc.offset_or_small_constant as u32 as u64; + match mv { + MachineValue::WasmStack(x) => { + stack_constants.insert(x, v); + *wasm_stack.last_mut().unwrap() = WasmAbstractValue::Const(v); + } + _ => {} // TODO + } + } + LocationType::ConstantIndex => { + let v = + llvm_map.constants[loc.offset_or_small_constant as usize].large_constant; + match mv { + MachineValue::WasmStack(x) => { + stack_constants.insert(x, v); + *wasm_stack.last_mut().unwrap() = WasmAbstractValue::Const(v); + } + _ => {} // TODO + } + } + LocationType::Direct => match mv { + MachineValue::WasmLocal(_) => { + assert_eq!(loc.location_size, 8); + assert!(loc.offset_or_small_constant < 0); + assert!( + X64Register::from_dwarf_regnum(loc.dwarf_regnum).unwrap() + == X64Register::GPR(GPR::RBP) + ); + let stack_offset = ((-loc.offset_or_small_constant) % 8) as usize; + assert!(stack_offset > 0 && stack_offset <= machine_stack_layout.len()); + machine_stack_layout[stack_offset - 1] = mv; + } + _ => unreachable!( + "Direct location type is not expected for values other than local" + ), + }, + LocationType::Indirect => { + assert_eq!(loc.location_size, 8); + assert!(loc.offset_or_small_constant < 0); + assert!( + X64Register::from_dwarf_regnum(loc.dwarf_regnum).unwrap() + == X64Register::GPR(GPR::RBP) + ); + let stack_offset = ((-loc.offset_or_small_constant) % 8) as usize; + assert!(stack_offset > 0 && stack_offset <= machine_stack_layout.len()); + machine_stack_layout[stack_offset - 1] = mv; + } + } + } + + assert_eq!(wasm_stack.len(), self.stack_count); + assert_eq!(wasm_locals.len(), self.local_count); + + let diff = MachineStateDiff { + last: None, + stack_push: machine_stack_layout, + stack_pop: 0, + reg_diff: regs, + wasm_stack_push: wasm_stack, + wasm_stack_pop: 0, + wasm_stack_private_depth: 0, + wasm_inst_offset: self.opcode_offset, + }; + let diff_id = fsm.diffs.len(); + fsm.diffs.push(diff); + + match self.kind { + StackmapEntryKind::FunctionHeader => { + fsm.locals = wasm_locals; + } + _ => { + assert_eq!(fsm.locals, wasm_locals); + } + } + let target_offset = (size_record.function_address as usize) + .checked_sub(code_addr) + .unwrap() + + map_record.instruction_offset as usize; + + match self.kind { + StackmapEntryKind::Loop => { + fsm.wasm_offset_to_target_offset + .insert(self.opcode_offset, SuspendOffset::Loop(target_offset)); + fsm.loop_offsets.insert( + target_offset, + OffsetInfo { + diff_id, + activate_offset: target_offset, + }, + ); + } + StackmapEntryKind::Call => { + fsm.wasm_offset_to_target_offset + .insert(self.opcode_offset, SuspendOffset::Call(target_offset)); + fsm.call_offsets.insert( + target_offset, + OffsetInfo { + diff_id, + activate_offset: target_offset, + }, + ); + } + StackmapEntryKind::Trappable => { + fsm.wasm_offset_to_target_offset + .insert(self.opcode_offset, SuspendOffset::Trappable(target_offset)); + fsm.trappable_offsets.insert( + target_offset, + OffsetInfo { + diff_id, + activate_offset: target_offset, + }, + ); + } + StackmapEntryKind::FunctionHeader => { + fsm.wasm_function_header_target_offset = Some(SuspendOffset::Loop(target_offset)); + } + } + } +} + #[derive(Clone, Debug, Default)] pub struct StackMap { pub version: u8, diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 8650cb4acff..9b1c289dfec 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -842,6 +842,7 @@ pub mod x64 { XMM7, } + #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum X64Register { GPR(GPR), XMM(XMM), @@ -854,5 +855,36 @@ pub mod x64 { 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, + }) + } } } From cc4f0e31a69a7087cff05bd2ae29ed2ed91f177c Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 25 Jul 2019 02:44:28 +0800 Subject: [PATCH 05/90] TwoHalves & trying to get cowsay to compile again --- lib/llvm-backend/src/backend.rs | 15 +++-- lib/llvm-backend/src/code.rs | 34 ++++++---- lib/llvm-backend/src/stackmap.rs | 53 +++++++++++---- lib/runtime-core/src/state.rs | 107 ++++++++++++++++++++++++++++--- 4 files changed, 170 insertions(+), 39 deletions(-) diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index 778f7ddbad2..d148c074c9d 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -1,4 +1,4 @@ -use super::stackmap::{self, StackmapRegistry}; +use super::stackmap::{self, StackmapRegistry, StkMapRecord}; use crate::intrinsics::Intrinsics; use inkwell::{ memory_buffer::MemoryBuffer, @@ -18,6 +18,7 @@ use std::{ ptr::{self, NonNull}, slice, str, sync::{Arc, Once}, + collections::BTreeMap, }; use wasmer_runtime_core::{ backend::{ @@ -304,7 +305,7 @@ impl LLVMBackend { }; if raw_stackmap.len() > 0 { let map = stackmap::StackMap::parse(raw_stackmap).unwrap(); - eprintln!("{:?}", map); + println!("{:?}", map); let (code_ptr, code_size) = unsafe { ( @@ -316,10 +317,16 @@ impl LLVMBackend { local_functions: Default::default(), total_size: code_size, }; + + let mut map_records: BTreeMap = BTreeMap::new(); + for r in &map.stk_map_records { + map_records.insert(r.patchpoint_id as usize, r); + } + let mut map_record_idx: usize = 0; for size_record in &map.stk_size_records { - for _ in 0..size_record.record_count { - let map_record = &map.stk_map_records[map_record_idx]; + for _ in 0..size_record.record_count as usize { + let map_record = map_records.get(&map_record_idx).expect("map record not found"); let map_entry = &stackmaps.entries[map_record_idx]; assert_eq!(map_record.patchpoint_id, map_record_idx as u64); map_record_idx += 1; diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 32131873fd7..be623a91fb8 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -447,6 +447,26 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let ctx = CtxType::new(module_info, function, cache_builder); self.ctx = Some(ctx); + + + { + let mut state = &mut self.state; + let builder = self.builder.as_ref().unwrap(); + let intrinsics = self.intrinsics.as_ref().unwrap(); + + let mut stackmaps = self.stackmaps.borrow_mut(); + emit_stack_map( + &intrinsics, + &builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::FunctionHeader, + &self.locals, + &state, + ::std::usize::MAX, + ); + } + Ok(()) } @@ -2582,20 +2602,6 @@ impl ModuleCodeGenerator let local_func_index = self.functions.len(); - { - let mut stackmaps = self.stackmaps.borrow_mut(); - emit_stack_map( - &intrinsics, - &builder, - local_func_index, - &mut *stackmaps, - StackmapEntryKind::FunctionHeader, - &locals, - &state, - ::std::usize::MAX, - ); - } - let code = LLVMFunctionCodeGenerator { state, context: Some(context), diff --git a/lib/llvm-backend/src/stackmap.rs b/lib/llvm-backend/src/stackmap.rs index e75148f242e..fa14985bdda 100644 --- a/lib/llvm-backend/src/stackmap.rs +++ b/lib/llvm-backend/src/stackmap.rs @@ -74,7 +74,7 @@ impl StackmapEntry { map_record: &StkMapRecord, msm: &mut ModuleStateMap, ) { - #[derive(Copy, Clone, Debug)] + #[derive(Clone, Debug)] enum RuntimeOrConstant { Runtime(MachineValue), Constant(u64), @@ -88,10 +88,9 @@ impl StackmapEntry { }); assert_eq!(self.value_semantics.len(), map_record.locations.len()); - assert!(size_record.stack_size % 8 == 0); + //assert!(size_record.stack_size % 8 == 0); // is this also aligned to 16 bytes? - let mut machine_stack_layout: Vec = - vec![MachineValue::Undefined; (size_record.stack_size as usize) / 8]; + let mut machine_stack_half_layout: Vec = Vec::new(); let mut regs: Vec<(RegisterIndex, MachineValue)> = vec![]; let mut stack_constants: HashMap = HashMap::new(); @@ -145,30 +144,38 @@ impl StackmapEntry { } LocationType::Direct => match mv { MachineValue::WasmLocal(_) => { - assert_eq!(loc.location_size, 8); - assert!(loc.offset_or_small_constant < 0); + assert_eq!(loc.location_size, 8); // the pointer itself assert!( X64Register::from_dwarf_regnum(loc.dwarf_regnum).unwrap() == X64Register::GPR(GPR::RBP) ); - let stack_offset = ((-loc.offset_or_small_constant) % 8) as usize; - assert!(stack_offset > 0 && stack_offset <= machine_stack_layout.len()); - machine_stack_layout[stack_offset - 1] = mv; + if loc.offset_or_small_constant >= 0 { + eprintln!("XXX: {}", loc.offset_or_small_constant); + } + assert!(loc.offset_or_small_constant < 0); + let stack_offset = ((-loc.offset_or_small_constant) / 4) as usize; + while stack_offset > machine_stack_half_layout.len() { + machine_stack_half_layout.push(MachineValue::Undefined); + } + assert!(stack_offset > 0 && stack_offset <= machine_stack_half_layout.len()); + machine_stack_half_layout[stack_offset - 1] = mv; } _ => unreachable!( "Direct location type is not expected for values other than local" ), }, LocationType::Indirect => { - assert_eq!(loc.location_size, 8); assert!(loc.offset_or_small_constant < 0); assert!( X64Register::from_dwarf_regnum(loc.dwarf_regnum).unwrap() == X64Register::GPR(GPR::RBP) ); - let stack_offset = ((-loc.offset_or_small_constant) % 8) as usize; - assert!(stack_offset > 0 && stack_offset <= machine_stack_layout.len()); - machine_stack_layout[stack_offset - 1] = mv; + let stack_offset = ((-loc.offset_or_small_constant) / 4) as usize; + while stack_offset > machine_stack_half_layout.len() { + machine_stack_half_layout.push(MachineValue::Undefined); + } + assert!(stack_offset > 0 && stack_offset <= machine_stack_half_layout.len()); + machine_stack_half_layout[stack_offset - 1] = mv; } } } @@ -176,6 +183,26 @@ impl StackmapEntry { assert_eq!(wasm_stack.len(), self.stack_count); assert_eq!(wasm_locals.len(), self.local_count); + if machine_stack_half_layout.len() % 2 != 0 { + machine_stack_half_layout.push(MachineValue::Undefined); + } + + let mut machine_stack_layout: Vec = Vec::with_capacity(machine_stack_half_layout.len() / 2); + + for i in 0..machine_stack_half_layout.len() / 2 { + let left = &machine_stack_half_layout[i * 2]; + let right = &machine_stack_half_layout[i * 2 + 1]; + let only_left = match *right { + MachineValue::Undefined => true, + _ => false, + }; + if only_left { + machine_stack_layout.push(left.clone()); + } else { + machine_stack_layout.push(MachineValue::TwoHalves(Box::new((right.clone(), left.clone())))); + } + } + let diff = MachineStateDiff { last: None, stack_push: machine_stack_layout, diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 9b1c289dfec..2e5559c86ee 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -35,7 +35,7 @@ pub struct MachineStateDiff { pub wasm_inst_offset: usize, // absolute value; not a diff. } -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Debug, Eq, PartialEq, Hash)] pub enum MachineValue { Undefined, Vmctx, @@ -44,6 +44,7 @@ pub enum MachineValue { ExplicitShadow, // indicates that all values above this are above the shadow region WasmStack(usize), WasmLocal(usize), + TwoHalves(Box<(MachineValue, MachineValue)>), // 32-bit values. TODO: optimize: add another type for inner "half" value to avoid boxing? } #[derive(Clone, Debug)] @@ -203,7 +204,7 @@ impl MachineState { .iter() .zip(old.stack_values.iter()) .enumerate() - .find(|&(_, (&a, &b))| a != b) + .find(|&(_, (a, b))| a != b) .map(|x| x.0) .unwrap_or(old.stack_values.len().min(self.stack_values.len())); assert_eq!(self.register_values.len(), old.register_values.len()); @@ -212,15 +213,15 @@ impl MachineState { .iter() .zip(old.register_values.iter()) .enumerate() - .filter(|&(_, (&a, &b))| a != b) - .map(|(i, (&a, _))| (RegisterIndex(i), a)) + .filter(|&(_, (a, b))| a != b) + .map(|(i, (a, _))| (RegisterIndex(i), a.clone())) .collect(); let first_diff_wasm_stack_depth: usize = self .wasm_stack .iter() .zip(old.wasm_stack.iter()) .enumerate() - .find(|&(_, (&a, &b))| a != b) + .find(|&(_, (a, b))| a != b) .map(|x| x.0) .unwrap_or(old.wasm_stack.len().min(self.wasm_stack.len())); MachineStateDiff { @@ -255,10 +256,10 @@ impl MachineStateDiff { state.stack_values.pop().unwrap(); } for v in &x.stack_push { - state.stack_values.push(*v); + state.stack_values.push(v.clone()); } - for &(index, v) in &x.reg_diff { - state.register_values[index.0] = v; + for &(index, ref v) in &x.reg_diff { + state.register_values[index.0] = v.clone(); } for _ in 0..x.wasm_stack_pop { state.wasm_stack.pop().unwrap(); @@ -488,6 +489,72 @@ pub mod x64 { } } } + MachineValue::TwoHalves(ref inner) => { + stack_offset -= 1; + // TODO: Cleanup + match inner.0 { + MachineValue::WasmStack(x) => { + match state.wasm_stack[x] { + WasmAbstractValue::Const(x) => { + assert!(x <= ::std::u32::MAX as u64); + stack[stack_offset] |= x; + } + WasmAbstractValue::Runtime => { + let v = f.stack[x].unwrap(); + assert!(v <= ::std::u32::MAX as u64); + stack[stack_offset] |= v; + } + } + } + MachineValue::WasmLocal(x) => { + stack_offset -= 1; + match fsm.locals[x] { + WasmAbstractValue::Const(x) => { + assert!(x <= ::std::u32::MAX as u64); + stack[stack_offset] |= x; + } + WasmAbstractValue::Runtime => { + let v = f.locals[x].unwrap(); + assert!(v <= ::std::u32::MAX as u64); + stack[stack_offset] |= v; + } + } + } + MachineValue::Undefined => {} + _ => unimplemented!("TwoHalves.0"), + } + match inner.1 { + MachineValue::WasmStack(x) => { + match state.wasm_stack[x] { + WasmAbstractValue::Const(x) => { + assert!(x <= ::std::u32::MAX as u64); + stack[stack_offset] |= x << 32; + } + WasmAbstractValue::Runtime => { + let v = f.stack[x].unwrap(); + assert!(v <= ::std::u32::MAX as u64); + stack[stack_offset] |= v << 32; + } + } + } + MachineValue::WasmLocal(x) => { + stack_offset -= 1; + match fsm.locals[x] { + WasmAbstractValue::Const(x) => { + assert!(x <= ::std::u32::MAX as u64); + stack[stack_offset] |= x << 32; + } + WasmAbstractValue::Runtime => { + let v = f.locals[x].unwrap(); + assert!(v <= ::std::u32::MAX as u64); + stack[stack_offset] |= v << 32; + } + } + } + MachineValue::Undefined => {} + _ => unimplemented!("TwoHalves.1"), + } + } } } if !got_explicit_shadow { @@ -785,6 +852,30 @@ pub mod x64 { wasm_locals[idx] = Some(*stack); stack = stack.offset(1); } + MachineValue::TwoHalves(ref inner) => { + let v = *stack; + stack = stack.offset(1); + match inner.0 { + MachineValue::WasmStack(idx) => { + wasm_stack[idx] = Some(v & 0xffffffffu64); + } + MachineValue::WasmLocal(idx) => { + wasm_locals[idx] = Some(v & 0xffffffffu64); + } + MachineValue::Undefined => {}, + _ => unimplemented!("TwoHalves.0 (read)") + } + match inner.1 { + MachineValue::WasmStack(idx) => { + wasm_stack[idx] = Some(v >> 32); + } + MachineValue::WasmLocal(idx) => { + wasm_locals[idx] = Some(v >> 32); + } + MachineValue::Undefined => {}, + _ => unimplemented!("TwoHalves.1 (read)") + } + } } } stack = stack.offset(1); // RBP From efb5277d1dccfe23765a0569baaaa05f2cf7d315 Mon Sep 17 00:00:00 2001 From: losfair Date: Sat, 27 Jul 2019 02:50:49 +0800 Subject: [PATCH 06/90] Stack parsing now works with LLVM. --- lib/llvm-backend/src/backend.rs | 73 +++++++++++++++++++++++--------- lib/llvm-backend/src/code.rs | 9 +++- lib/llvm-backend/src/stackmap.rs | 41 ++++++++---------- lib/runtime-core/src/fault.rs | 14 ++++-- src/bin/wasmer.rs | 63 ++++++++++++++------------- 5 files changed, 122 insertions(+), 78 deletions(-) diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index d148c074c9d..90332087cb5 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -1,4 +1,4 @@ -use super::stackmap::{self, StackmapRegistry, StkMapRecord}; +use super::stackmap::{self, StackmapRegistry, StkMapRecord, StkSizeRecord}; use crate::intrinsics::Intrinsics; use inkwell::{ memory_buffer::MemoryBuffer, @@ -246,6 +246,7 @@ impl LLVMBackend { module: Module, _intrinsics: Intrinsics, stackmaps: &StackmapRegistry, + module_info: &ModuleInfo, ) -> (Self, LLVMCache) { Target::initialize_x86(&InitializationConfig { asm_parser: true, @@ -305,7 +306,6 @@ impl LLVMBackend { }; if raw_stackmap.len() > 0 { let map = stackmap::StackMap::parse(raw_stackmap).unwrap(); - println!("{:?}", map); let (code_ptr, code_size) = unsafe { ( @@ -318,40 +318,73 @@ impl LLVMBackend { total_size: code_size, }; + let mut local_func_id_to_addr: Vec = Vec::new(); + + // All local functions. + for index in module_info.imported_functions.len()..module_info.func_assoc.len() { + let name = if cfg!(target_os = "macos") { + format!("_fn{}", index) + } else { + format!("fn{}", index) + }; + + let c_str = CString::new(name).unwrap(); + let ptr = unsafe { get_func_symbol(module, c_str.as_ptr()) }; + + assert!(!ptr.is_null()); + local_func_id_to_addr.push(ptr as usize); + } + + let mut addr_to_size_record: BTreeMap = BTreeMap::new(); + + for record in &map.stk_size_records { + addr_to_size_record.insert(record.function_address as usize, record); + } + let mut map_records: BTreeMap = BTreeMap::new(); + for r in &map.stk_map_records { map_records.insert(r.patchpoint_id as usize, r); } - let mut map_record_idx: usize = 0; - for size_record in &map.stk_size_records { - for _ in 0..size_record.record_count as usize { - let map_record = map_records.get(&map_record_idx).expect("map record not found"); - let map_entry = &stackmaps.entries[map_record_idx]; - assert_eq!(map_record.patchpoint_id, map_record_idx as u64); - map_record_idx += 1; - - map_entry.populate_msm( + for (i, entry) in stackmaps.entries.iter().enumerate() { + if let Some(map_record) = map_records.get(&i) { + assert_eq!(i, map_record.patchpoint_id as usize); + let addr = local_func_id_to_addr[entry.local_function_id]; + let size_record = *addr_to_size_record.get(&addr).expect("size_record not found"); + entry.populate_msm( code_ptr as usize, &map, size_record, map_record, &mut msm, ); + } else { + // TODO: optimized out? } } + + //println!("MSM: {:?}", msm); + + ( + Self { + module, + buffer: Arc::clone(&buffer), + msm: Some(msm), + }, + LLVMCache { buffer }, + ) } else { eprintln!("WARNING: No stack map"); + ( + Self { + module, + buffer: Arc::clone(&buffer), + msm: None, + }, + LLVMCache { buffer }, + ) } - - ( - Self { - module, - buffer: Arc::clone(&buffer), - msm: None, - }, - LLVMCache { buffer }, - ) } pub unsafe fn from_buffer(memory: Memory) -> Result<(Self, LLVMCache), String> { diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index be623a91fb8..1484f26088e 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -849,7 +849,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { &self.locals, state, offset, - ) + ); + builder.build_call( + intrinsics.trap, + &[], + "trap", + ); } builder.build_call( @@ -2675,7 +2680,7 @@ impl ModuleCodeGenerator let stackmaps = self.stackmaps.borrow(); let (backend, cache_gen) = - LLVMBackend::new(self.module, self.intrinsics.take().unwrap(), &*stackmaps); + LLVMBackend::new(self.module, self.intrinsics.take().unwrap(), &*stackmaps, module_info); Ok((backend, Box::new(cache_gen))) } diff --git a/lib/llvm-backend/src/stackmap.rs b/lib/llvm-backend/src/stackmap.rs index fa14985bdda..4f95efe8605 100644 --- a/lib/llvm-backend/src/stackmap.rs +++ b/lib/llvm-backend/src/stackmap.rs @@ -88,9 +88,13 @@ impl StackmapEntry { }); assert_eq!(self.value_semantics.len(), map_record.locations.len()); - //assert!(size_record.stack_size % 8 == 0); // is this also aligned to 16 bytes? - let mut machine_stack_half_layout: Vec = Vec::new(); + // System V requires 16-byte alignment before each call instruction. + // Considering the saved rbp we need to ensure the stack size % 16 always equals to 8. + assert!(size_record.stack_size % 16 == 8); + + // Layout begins just below saved rbp. (push rbp; mov rbp, rsp) + let mut machine_stack_half_layout: Vec = vec![MachineValue::Undefined; (size_record.stack_size - 8) as usize / 4]; let mut regs: Vec<(RegisterIndex, MachineValue)> = vec![]; let mut stack_constants: HashMap = HashMap::new(); @@ -150,15 +154,13 @@ impl StackmapEntry { == X64Register::GPR(GPR::RBP) ); if loc.offset_or_small_constant >= 0 { - eprintln!("XXX: {}", loc.offset_or_small_constant); - } - assert!(loc.offset_or_small_constant < 0); - let stack_offset = ((-loc.offset_or_small_constant) / 4) as usize; - while stack_offset > machine_stack_half_layout.len() { - machine_stack_half_layout.push(MachineValue::Undefined); + // FIXME: parameters passed on stack? + //eprintln!("XXX: {}", loc.offset_or_small_constant); + } else { + let stack_offset = ((-loc.offset_or_small_constant) / 4) as usize; + assert!(stack_offset > 0 && stack_offset <= machine_stack_half_layout.len()); + machine_stack_half_layout[stack_offset - 1] = mv; } - assert!(stack_offset > 0 && stack_offset <= machine_stack_half_layout.len()); - machine_stack_half_layout[stack_offset - 1] = mv; } _ => unreachable!( "Direct location type is not expected for values other than local" @@ -171,9 +173,6 @@ impl StackmapEntry { == X64Register::GPR(GPR::RBP) ); let stack_offset = ((-loc.offset_or_small_constant) / 4) as usize; - while stack_offset > machine_stack_half_layout.len() { - machine_stack_half_layout.push(MachineValue::Undefined); - } assert!(stack_offset > 0 && stack_offset <= machine_stack_half_layout.len()); machine_stack_half_layout[stack_offset - 1] = mv; } @@ -183,23 +182,19 @@ impl StackmapEntry { assert_eq!(wasm_stack.len(), self.stack_count); assert_eq!(wasm_locals.len(), self.local_count); - if machine_stack_half_layout.len() % 2 != 0 { - machine_stack_half_layout.push(MachineValue::Undefined); - } - let mut machine_stack_layout: Vec = Vec::with_capacity(machine_stack_half_layout.len() / 2); for i in 0..machine_stack_half_layout.len() / 2 { - let left = &machine_stack_half_layout[i * 2]; - let right = &machine_stack_half_layout[i * 2 + 1]; - let only_left = match *right { + let major = &machine_stack_half_layout[i * 2 + 1]; // mod 8 == 0 + let minor = &machine_stack_half_layout[i * 2]; // mod 8 == 4 + let only_major = match *minor { MachineValue::Undefined => true, _ => false, }; - if only_left { - machine_stack_layout.push(left.clone()); + if only_major { + machine_stack_layout.push(major.clone()); } else { - machine_stack_layout.push(MachineValue::TwoHalves(Box::new((right.clone(), left.clone())))); + machine_stack_layout.push(MachineValue::TwoHalves(Box::new((major.clone(), minor.clone())))); } } diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index 119aeae0455..871b8f6facb 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -40,6 +40,7 @@ struct UnwindInfo { thread_local! { static UNWIND: UnsafeCell> = UnsafeCell::new(None); + static CURRENT_CTX: UnsafeCell<*mut vm::Ctx> = UnsafeCell::new(::std::ptr::null_mut()); } struct InterruptSignalMem(*mut u8); @@ -68,6 +69,15 @@ lazy_static! { } static INTERRUPT_SIGNAL_DELIVERED: AtomicBool = AtomicBool::new(false); +pub unsafe fn with_ctx R>(ctx: *mut vm::Ctx, cb: F) -> R { + let addr = CURRENT_CTX.with(|x| x.get()); + let old = *addr; + *addr = ctx; + let ret = cb(); + *addr = old; + ret +} + pub unsafe fn get_wasm_interrupt_signal_mem() -> *mut u8 { INTERRUPT_SIGNAL_MEM.0 } @@ -209,9 +219,7 @@ extern "C" fn signal_trap_handler( _ => {} } - // TODO: make this safer - let ctx = &mut *(fault.known_registers[X64Register::GPR(GPR::R15).to_index().0].unwrap() - as *mut vm::Ctx); + 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 msm = (*ctx.module) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 070acd9e8a4..9f96738000e 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -113,7 +113,7 @@ struct Run { loader: Option, /// Path to previously saved instance image to resume. - #[cfg(feature = "backend-singlepass")] + #[cfg(any(feature = "backend-singlepass", feature = "backend-llvm"))] #[structopt(long = "resume")] resume: Option, @@ -512,10 +512,10 @@ fn execute_wasm(options: &Run) -> Result<(), String> { let start: Func<(), ()> = instance.func("_start").map_err(|e| format!("{:?}", e))?; - #[cfg(feature = "backend-singlepass")] + #[cfg(any(feature = "backend-singlepass", feature = "backend-llvm"))] unsafe { - if options.backend == Backend::Singlepass { - use wasmer_runtime_core::fault::{catch_unsafe_unwind, ensure_sighandler}; + if options.backend == Backend::Singlepass || options.backend == Backend::LLVM { + use wasmer_runtime_core::fault::{catch_unsafe_unwind, ensure_sighandler, with_ctx}; use wasmer_runtime_core::state::{ x64::invoke_call_return_on_stack, InstanceImage, }; @@ -537,29 +537,32 @@ fn execute_wasm(options: &Run) -> Result<(), String> { let breakpoints = instance.module.runnable_module.get_breakpoints(); loop { - let ret = if let Some(image) = image.take() { - let msm = instance - .module - .runnable_module - .get_module_state_map() - .unwrap(); - let code_base = - instance.module.runnable_module.get_code().unwrap().as_ptr() - as usize; - invoke_call_return_on_stack( - &msm, - code_base, - image, - instance.context_mut(), - breakpoints.clone(), - ) - .map(|_| ()) - } else { - catch_unsafe_unwind( - || start_raw(instance.context_mut()), - breakpoints.clone(), - ) - }; + let ctx = instance.context_mut() as *mut _; + let ret = with_ctx(ctx, || { + if let Some(image) = image.take() { + let msm = instance + .module + .runnable_module + .get_module_state_map() + .unwrap(); + let code_base = + instance.module.runnable_module.get_code().unwrap().as_ptr() + as usize; + invoke_call_return_on_stack( + &msm, + code_base, + image, + instance.context_mut(), + breakpoints.clone(), + ) + .map(|_| ()) + } else { + catch_unsafe_unwind( + || start_raw(instance.context_mut()), + breakpoints.clone(), + ) + } + }); if let Err(e) = ret { if let Some(new_image) = e.downcast_ref::() { let op = interactive_shell(InteractiveShellContext { @@ -619,18 +622,18 @@ fn execute_wasm(options: &Run) -> Result<(), String> { Ok(()) } -#[cfg(feature = "backend-singlepass")] +#[cfg(any(feature = "backend-singlepass", feature = "backend-llvm"))] struct InteractiveShellContext { image: Option, } -#[cfg(feature = "backend-singlepass")] +#[cfg(any(feature = "backend-singlepass", feature = "backend-llvm"))] #[derive(Debug)] enum ShellExitOperation { ContinueWith(wasmer_runtime_core::state::InstanceImage), } -#[cfg(feature = "backend-singlepass")] +#[cfg(any(feature = "backend-singlepass", feature = "backend-llvm"))] fn interactive_shell(mut ctx: InteractiveShellContext) -> ShellExitOperation { use std::io::Write; From 0a7f95ee066eb7c90c08da812bf5982e5c6c455f Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 30 Jul 2019 22:25:15 +0800 Subject: [PATCH 07/90] Allow a range of instruction offsets to be used in ip lookup. --- lib/llvm-backend/src/backend.rs | 29 ++++++--- lib/llvm-backend/src/code.rs | 97 +++++++++++++++++++++++++++--- lib/llvm-backend/src/intrinsics.rs | 25 ++++++++ lib/llvm-backend/src/stackmap.rs | 70 ++++++++++++++++----- 4 files changed, 191 insertions(+), 30 deletions(-) diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index 90332087cb5..058b91de04a 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -12,13 +12,13 @@ use libc::{ }; use std::{ any::Any, + collections::BTreeMap, ffi::{c_void, CString}, mem, ops::Deref, ptr::{self, NonNull}, slice, str, sync::{Arc, Once}, - collections::BTreeMap, }; use wasmer_runtime_core::{ backend::{ @@ -347,16 +347,31 @@ impl LLVMBackend { map_records.insert(r.patchpoint_id as usize, r); } - for (i, entry) in stackmaps.entries.iter().enumerate() { - if let Some(map_record) = map_records.get(&i) { - assert_eq!(i, map_record.patchpoint_id as usize); - let addr = local_func_id_to_addr[entry.local_function_id]; - let size_record = *addr_to_size_record.get(&addr).expect("size_record not found"); - entry.populate_msm( + for ((start_id, start_entry), (end_id, end_entry)) in stackmaps + .entries + .iter() + .enumerate() + .step_by(2) + .zip(stackmaps.entries.iter().enumerate().skip(1).step_by(2)) + { + if let Some(map_record) = map_records.get(&start_id) { + assert_eq!(start_id, map_record.patchpoint_id as usize); + assert!(start_entry.is_start); + assert!(!end_entry.is_start); + + let end_record = map_records.get(&end_id); + + let addr = local_func_id_to_addr[start_entry.local_function_id]; + let size_record = *addr_to_size_record + .get(&addr) + .expect("size_record not found"); + + start_entry.populate_msm( code_ptr as usize, &map, size_record, map_record, + end_record.map(|x| (end_entry, *x)), &mut msm, ); } else { diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 1484f26088e..9c11103e930 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -342,6 +342,38 @@ fn emit_stack_map( stack_count: state.stack.len(), opcode_offset, value_semantics, + is_start: true, + }); +} + +fn finalize_opcode_stack_map( + intrinsics: &Intrinsics, + builder: &Builder, + local_function_id: usize, + target: &mut StackmapRegistry, + kind: StackmapEntryKind, + opcode_offset: usize, +) { + let stackmap_id = target.entries.len(); + builder.build_call( + intrinsics.experimental_stackmap, + &[ + intrinsics + .i64_ty + .const_int(stackmap_id as u64, false) + .as_basic_value_enum(), + intrinsics.i32_ty.const_int(0, false).as_basic_value_enum(), + ], + "opcode_stack_map_end", + ); + target.entries.push(StackmapEntry { + kind, + local_function_id, + local_count: 0, + stack_count: 0, + opcode_offset, + value_semantics: vec![], + is_start: false, }); } @@ -448,7 +480,6 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { self.ctx = Some(ctx); - { let mut state = &mut self.state; let builder = self.builder.as_ref().unwrap(); @@ -465,6 +496,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { &state, ::std::usize::MAX, ); + finalize_opcode_stack_map( + &intrinsics, + &builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::FunctionHeader, + ::std::usize::MAX, + ); } Ok(()) @@ -574,7 +613,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { &self.locals, state, offset, - ) + ); + let signal_mem = ctx.signal_mem(); + let iv = builder + .build_store(signal_mem, context.i8_type().const_int(0 as u64, false)); + iv.set_volatile(true); + finalize_opcode_stack_map( + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Loop, + offset, + ); } state.push_loop(loop_body, loop_next, phis); @@ -850,10 +901,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state, offset, ); - builder.build_call( - intrinsics.trap, - &[], - "trap", + builder.build_call(intrinsics.trap, &[], "trap"); + finalize_opcode_stack_map( + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Trappable, + offset + 1, ); } @@ -1008,6 +1063,17 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) } let call_site = builder.build_call(func_ptr, ¶ms, &state.var_name()); + if let Some(offset) = opcode_offset { + let mut stackmaps = self.stackmaps.borrow_mut(); + finalize_opcode_stack_map( + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Call, + offset, + ) + } if let Some(basic_value) = call_site.try_as_basic_value().left() { match func_sig.returns().len() { @@ -1186,6 +1252,17 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) } let call_site = builder.build_call(typed_func_ptr, &args, "indirect_call"); + if let Some(offset) = opcode_offset { + let mut stackmaps = self.stackmaps.borrow_mut(); + finalize_opcode_stack_map( + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Call, + offset, + ) + } match wasmer_fn_sig.returns() { [] => {} @@ -2679,8 +2756,12 @@ impl ModuleCodeGenerator let stackmaps = self.stackmaps.borrow(); - let (backend, cache_gen) = - LLVMBackend::new(self.module, self.intrinsics.take().unwrap(), &*stackmaps, module_info); + let (backend, cache_gen) = LLVMBackend::new( + self.module, + self.intrinsics.take().unwrap(), + &*stackmaps, + module_info, + ); Ok((backend, Box::new(cache_gen))) } diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index 41526ee646d..89d8f5fcd2f 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -445,6 +445,8 @@ pub struct CtxType<'a> { info: &'a ModuleInfo, cache_builder: Builder, + cached_signal_mem: Option, + cached_memories: HashMap, cached_tables: HashMap, cached_sigindices: HashMap, @@ -470,6 +472,8 @@ impl<'a> CtxType<'a> { info, cache_builder, + cached_signal_mem: None, + cached_memories: HashMap::new(), cached_tables: HashMap::new(), cached_sigindices: HashMap::new(), @@ -484,6 +488,27 @@ impl<'a> CtxType<'a> { self.ctx_ptr_value.as_basic_value_enum() } + pub fn signal_mem(&mut self) -> PointerValue { + if let Some(x) = self.cached_signal_mem { + return x; + } + + let (ctx_ptr_value, cache_builder) = (self.ctx_ptr_value, &self.cache_builder); + + let ptr_ptr = unsafe { + cache_builder.build_struct_gep( + ctx_ptr_value, + offset_to_index(Ctx::offset_interrupt_signal_mem()), + "interrupt_signal_mem_ptr", + ) + }; + let ptr = cache_builder + .build_load(ptr_ptr, "interrupt_signal_mem") + .into_pointer_value(); + self.cached_signal_mem = Some(ptr); + ptr + } + pub fn memory(&mut self, index: MemoryIndex, intrinsics: &Intrinsics) -> MemoryCache { let (cached_memories, info, ctx_ptr_value, cache_builder) = ( &mut self.cached_memories, diff --git a/lib/llvm-backend/src/stackmap.rs b/lib/llvm-backend/src/stackmap.rs index 4f95efe8605..1a6ad7e20dc 100644 --- a/lib/llvm-backend/src/stackmap.rs +++ b/lib/llvm-backend/src/stackmap.rs @@ -22,6 +22,7 @@ pub struct StackmapEntry { pub value_semantics: Vec, pub local_count: usize, pub stack_count: usize, + pub is_start: bool, } #[derive(Debug, Clone)] @@ -30,7 +31,7 @@ pub enum ValueSemantic { WasmStack(usize), } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum StackmapEntryKind { FunctionHeader, Loop, @@ -72,6 +73,7 @@ impl StackmapEntry { llvm_map: &StackMap, size_record: &StkSizeRecord, map_record: &StkMapRecord, + end: Option<(&StackmapEntry, &StkMapRecord)>, msm: &mut ModuleStateMap, ) { #[derive(Clone, Debug)] @@ -80,12 +82,23 @@ impl StackmapEntry { Constant(u64), } - let fsm = msm - .local_functions - .entry(self.local_function_id) - .or_insert_with(|| { - FunctionStateMap::new(new_machine_state(), self.local_function_id, 0, vec![]) - }); + let func_base_addr = (size_record.function_address as usize) + .checked_sub(code_addr) + .unwrap(); + let target_offset = func_base_addr + map_record.instruction_offset as usize; + + if msm.local_functions.len() == self.local_function_id { + assert_eq!(self.kind, StackmapEntryKind::FunctionHeader); + msm.local_functions.insert( + target_offset, + FunctionStateMap::new(new_machine_state(), self.local_function_id, 0, vec![]), + ); + } else if msm.local_functions.len() == self.local_function_id + 1 { + } else { + panic!("unordered local functions"); + } + + let (_, fsm) = msm.local_functions.iter_mut().last().unwrap(); assert_eq!(self.value_semantics.len(), map_record.locations.len()); @@ -94,7 +107,8 @@ impl StackmapEntry { assert!(size_record.stack_size % 16 == 8); // Layout begins just below saved rbp. (push rbp; mov rbp, rsp) - let mut machine_stack_half_layout: Vec = vec![MachineValue::Undefined; (size_record.stack_size - 8) as usize / 4]; + let mut machine_stack_half_layout: Vec = + vec![MachineValue::Undefined; (size_record.stack_size - 8) as usize / 4]; let mut regs: Vec<(RegisterIndex, MachineValue)> = vec![]; let mut stack_constants: HashMap = HashMap::new(); @@ -158,7 +172,9 @@ impl StackmapEntry { //eprintln!("XXX: {}", loc.offset_or_small_constant); } else { let stack_offset = ((-loc.offset_or_small_constant) / 4) as usize; - assert!(stack_offset > 0 && stack_offset <= machine_stack_half_layout.len()); + assert!( + stack_offset > 0 && stack_offset <= machine_stack_half_layout.len() + ); machine_stack_half_layout[stack_offset - 1] = mv; } } @@ -182,7 +198,8 @@ impl StackmapEntry { assert_eq!(wasm_stack.len(), self.stack_count); assert_eq!(wasm_locals.len(), self.local_count); - let mut machine_stack_layout: Vec = Vec::with_capacity(machine_stack_half_layout.len() / 2); + let mut machine_stack_layout: Vec = + Vec::with_capacity(machine_stack_half_layout.len() / 2); for i in 0..machine_stack_half_layout.len() / 2 { let major = &machine_stack_half_layout[i * 2 + 1]; // mod 8 == 0 @@ -194,7 +211,10 @@ impl StackmapEntry { if only_major { machine_stack_layout.push(major.clone()); } else { - machine_stack_layout.push(MachineValue::TwoHalves(Box::new((major.clone(), minor.clone())))); + machine_stack_layout.push(MachineValue::TwoHalves(Box::new(( + major.clone(), + minor.clone(), + )))); } } @@ -219,10 +239,19 @@ impl StackmapEntry { assert_eq!(fsm.locals, wasm_locals); } } - let target_offset = (size_record.function_address as usize) - .checked_sub(code_addr) - .unwrap() - + map_record.instruction_offset as usize; + + let end_offset = { + if let Some(end) = end { + let (end_entry, end_record) = end; + assert_eq!(end_entry.is_start, false); + assert_eq!(self.opcode_offset, end_entry.opcode_offset); + let end_offset = func_base_addr + end_record.instruction_offset as usize; + assert!(end_offset >= target_offset); + end_offset + } else { + target_offset + 1 + } + }; match self.kind { StackmapEntryKind::Loop => { @@ -231,6 +260,7 @@ impl StackmapEntry { fsm.loop_offsets.insert( target_offset, OffsetInfo { + end_offset, diff_id, activate_offset: target_offset, }, @@ -242,6 +272,7 @@ impl StackmapEntry { fsm.call_offsets.insert( target_offset, OffsetInfo { + end_offset: end_offset + 1, // The return address is just after 'call' instruction. Offset by one here. diff_id, activate_offset: target_offset, }, @@ -253,6 +284,7 @@ impl StackmapEntry { fsm.trappable_offsets.insert( target_offset, OffsetInfo { + end_offset, diff_id, activate_offset: target_offset, }, @@ -260,6 +292,14 @@ impl StackmapEntry { } StackmapEntryKind::FunctionHeader => { fsm.wasm_function_header_target_offset = Some(SuspendOffset::Loop(target_offset)); + fsm.loop_offsets.insert( + target_offset, + OffsetInfo { + end_offset, + diff_id, + activate_offset: target_offset, + }, + ); } } } From 283676af2b8257a292769d4cd69d63fee43f0b74 Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 30 Jul 2019 22:25:37 +0800 Subject: [PATCH 08/90] Add .clone() to fix singlepass. --- lib/singlepass-backend/src/codegen_x64.rs | 14 ++++++++++---- lib/singlepass-backend/src/machine.rs | 6 +++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 7bc6581bae3..afd358cc2b6 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -557,6 +557,7 @@ impl X64FunctionCode { fsm.trappable_offsets.insert( offset, OffsetInfo { + end_offset: offset + 1, activate_offset: offset, diff_id: state_diff_id, }, @@ -1179,7 +1180,7 @@ impl X64FunctionCode { let used_gprs = m.get_used_gprs(); 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]; + let content = m.state.register_values[X64Register::GPR(*r).to_index().0].clone(); assert!(content != MachineValue::Undefined); m.state.stack_values.push(content); } @@ -1204,7 +1205,7 @@ impl X64FunctionCode { ); } for r in used_xmms.iter().rev() { - let content = m.state.register_values[X64Register::XMM(*r).to_index().0]; + let content = m.state.register_values[X64Register::XMM(*r).to_index().0].clone(); assert!(content != MachineValue::Undefined); m.state.stack_values.push(content); } @@ -1244,7 +1245,8 @@ impl X64FunctionCode { Location::Memory(_, _) => { match *param { Location::GPR(x) => { - let content = m.state.register_values[X64Register::GPR(x).to_index().0]; + let content = + m.state.register_values[X64Register::GPR(x).to_index().0].clone(); // FIXME: There might be some corner cases (release -> emit_call_sysv -> acquire?) that cause this assertion to fail. // Hopefully nothing would be incorrect at runtime. @@ -1252,7 +1254,8 @@ impl X64FunctionCode { m.state.stack_values.push(content); } Location::XMM(x) => { - let content = m.state.register_values[X64Register::XMM(x).to_index().0]; + let content = + m.state.register_values[X64Register::XMM(x).to_index().0].clone(); //assert!(content != MachineValue::Undefined); m.state.stack_values.push(content); } @@ -1335,6 +1338,7 @@ impl X64FunctionCode { fsm.call_offsets.insert( offset, OffsetInfo { + end_offset: offset + 1, activate_offset: offset, diff_id: state_diff_id, }, @@ -1694,6 +1698,7 @@ impl FunctionCodeGenerator for X64FunctionCode { self.fsm.loop_offsets.insert( a.get_offset().0, OffsetInfo { + end_offset: a.get_offset().0 + 1, activate_offset, diff_id: state_diff_id, }, @@ -3958,6 +3963,7 @@ impl FunctionCodeGenerator for X64FunctionCode { self.fsm.loop_offsets.insert( a.get_offset().0, OffsetInfo { + end_offset: a.get_offset().0 + 1, activate_offset, diff_id: state_diff_id, }, diff --git a/lib/singlepass-backend/src/machine.rs b/lib/singlepass-backend/src/machine.rs index b09d0bf859f..fdabfca9a60 100644 --- a/lib/singlepass-backend/src/machine.rs +++ b/lib/singlepass-backend/src/machine.rs @@ -157,12 +157,12 @@ impl Machine { }; if let Location::GPR(x) = loc { self.used_gprs.insert(x); - self.state.register_values[X64Register::GPR(x).to_index().0] = *mv; + self.state.register_values[X64Register::GPR(x).to_index().0] = mv.clone(); } else if let Location::XMM(x) = loc { self.used_xmms.insert(x); - self.state.register_values[X64Register::XMM(x).to_index().0] = *mv; + self.state.register_values[X64Register::XMM(x).to_index().0] = mv.clone(); } else { - self.state.stack_values.push(*mv); + self.state.stack_values.push(mv.clone()); } self.state.wasm_stack.push(WasmAbstractValue::Runtime); ret.push(loc); From 4f567036572dd4d6d8de271b530c736fc1f4d9f1 Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 30 Jul 2019 22:25:58 +0800 Subject: [PATCH 09/90] Support runtime tier switching. --- lib/runtime-core/src/state.rs | 116 +++++++++++++--------------------- src/bin/wasmer.rs | 95 ++++++++++++++++++++++------ 2 files changed, 120 insertions(+), 91 deletions(-) diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 2e5559c86ee..81dcdbdcd7d 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -70,6 +70,7 @@ pub enum SuspendOffset { #[derive(Clone, Debug)] pub struct OffsetInfo { + pub end_offset: usize, // excluded bound pub diff_id: usize, pub activate_offset: usize, } @@ -101,7 +102,12 @@ pub struct InstanceImage { } impl ModuleStateMap { - fn lookup_call_ip(&self, ip: usize, base: usize) -> Option<(&FunctionStateMap, MachineState)> { + fn lookup_ip &BTreeMap>( + &self, + ip: usize, + base: usize, + offset_table_provider: F, + ) -> Option<(&FunctionStateMap, MachineState)> { if ip < base || ip - base >= self.total_size { None } else { @@ -111,9 +117,14 @@ impl ModuleStateMap { .last() .unwrap(); - match fsm.call_offsets.get(&(ip - base)) { - Some(x) => { - if x.diff_id < fsm.diffs.len() { + match offset_table_provider(fsm) + .range((Unbounded, Included(&(ip - base)))) + .last() + { + Some((_, x)) => { + if ip - base >= x.end_offset { + None + } else if x.diff_id < fsm.diffs.len() { Some((fsm, fsm.diffs[x.diff_id].build_state(fsm))) } else { None @@ -123,55 +134,20 @@ impl ModuleStateMap { } } } + fn lookup_call_ip(&self, ip: usize, base: usize) -> Option<(&FunctionStateMap, MachineState)> { + self.lookup_ip(ip, base, |fsm| &fsm.call_offsets) + } fn lookup_trappable_ip( &self, ip: usize, base: usize, ) -> Option<(&FunctionStateMap, MachineState)> { - if ip < base || ip - base >= self.total_size { - None - } else { - let (_, fsm) = self - .local_functions - .range((Unbounded, Included(&(ip - base)))) - .last() - .unwrap(); - - match fsm.trappable_offsets.get(&(ip - base)) { - Some(x) => { - if x.diff_id < fsm.diffs.len() { - Some((fsm, fsm.diffs[x.diff_id].build_state(fsm))) - } else { - None - } - } - None => None, - } - } + self.lookup_ip(ip, base, |fsm| &fsm.trappable_offsets) } fn lookup_loop_ip(&self, ip: usize, base: usize) -> Option<(&FunctionStateMap, MachineState)> { - if ip < base || ip - base >= self.total_size { - None - } else { - let (_, fsm) = self - .local_functions - .range((Unbounded, Included(&(ip - base)))) - .last() - .unwrap(); - - match fsm.loop_offsets.get(&(ip - base)) { - Some(x) => { - if x.diff_id < fsm.diffs.len() { - Some((fsm, fsm.diffs[x.diff_id].build_state(fsm))) - } else { - None - } - } - None => None, - } - } + self.lookup_ip(ip, base, |fsm| &fsm.loop_offsets) } } @@ -493,19 +469,17 @@ pub mod x64 { stack_offset -= 1; // TODO: Cleanup match inner.0 { - MachineValue::WasmStack(x) => { - match state.wasm_stack[x] { - WasmAbstractValue::Const(x) => { - assert!(x <= ::std::u32::MAX as u64); - stack[stack_offset] |= x; - } - WasmAbstractValue::Runtime => { - let v = f.stack[x].unwrap(); - assert!(v <= ::std::u32::MAX as u64); - stack[stack_offset] |= v; - } + MachineValue::WasmStack(x) => match state.wasm_stack[x] { + WasmAbstractValue::Const(x) => { + assert!(x <= ::std::u32::MAX as u64); + stack[stack_offset] |= x; } - } + WasmAbstractValue::Runtime => { + let v = f.stack[x].unwrap(); + assert!(v <= ::std::u32::MAX as u64); + stack[stack_offset] |= v; + } + }, MachineValue::WasmLocal(x) => { stack_offset -= 1; match fsm.locals[x] { @@ -524,19 +498,17 @@ pub mod x64 { _ => unimplemented!("TwoHalves.0"), } match inner.1 { - MachineValue::WasmStack(x) => { - match state.wasm_stack[x] { - WasmAbstractValue::Const(x) => { - assert!(x <= ::std::u32::MAX as u64); - stack[stack_offset] |= x << 32; - } - WasmAbstractValue::Runtime => { - let v = f.stack[x].unwrap(); - assert!(v <= ::std::u32::MAX as u64); - stack[stack_offset] |= v << 32; - } + MachineValue::WasmStack(x) => match state.wasm_stack[x] { + WasmAbstractValue::Const(x) => { + assert!(x <= ::std::u32::MAX as u64); + stack[stack_offset] |= x << 32; } - } + WasmAbstractValue::Runtime => { + let v = f.stack[x].unwrap(); + assert!(v <= ::std::u32::MAX as u64); + stack[stack_offset] |= v << 32; + } + }, MachineValue::WasmLocal(x) => { stack_offset -= 1; match fsm.locals[x] { @@ -862,8 +834,8 @@ pub mod x64 { MachineValue::WasmLocal(idx) => { wasm_locals[idx] = Some(v & 0xffffffffu64); } - MachineValue::Undefined => {}, - _ => unimplemented!("TwoHalves.0 (read)") + MachineValue::Undefined => {} + _ => unimplemented!("TwoHalves.0 (read)"), } match inner.1 { MachineValue::WasmStack(idx) => { @@ -872,8 +844,8 @@ pub mod x64 { MachineValue::WasmLocal(idx) => { wasm_locals[idx] = Some(v >> 32); } - MachineValue::Undefined => {}, - _ => unimplemented!("TwoHalves.1 (read)") + MachineValue::Undefined => {} + _ => unimplemented!("TwoHalves.1 (read)"), } } } diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 9f96738000e..8ad45f9f1e2 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -320,16 +320,9 @@ fn execute_wasm(options: &Run) -> Result<(), String> { .map_err(|e| format!("Can't convert from wast to wasm: {:?}", e))?; } - let compiler: Box = match options.backend { - #[cfg(feature = "backend-singlepass")] - Backend::Singlepass => Box::new(SinglePassCompiler::new()), - #[cfg(not(feature = "backend-singlepass"))] - Backend::Singlepass => return Err("The singlepass backend is not enabled".to_string()), - Backend::Cranelift => Box::new(CraneliftCompiler::new()), - #[cfg(feature = "backend-llvm")] - Backend::LLVM => Box::new(LLVMCompiler::new()), - #[cfg(not(feature = "backend-llvm"))] - Backend::LLVM => return Err("the llvm backend is not enabled".to_string()), + let compiler: Box = match get_compiler_by_backend(options.backend) { + Some(x) => x, + None => return Err("the requested backend is not enabled".into()), }; let track_state = !options.no_track_state; @@ -348,7 +341,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { webassembly::compile_with_config_with( &wasm_binary[..], CompilerConfig { - symbol_map: em_symbol_map, + symbol_map: em_symbol_map.clone(), memory_bound_check_mode: MemoryBoundCheckMode::Disable, enforce_stack_check: true, track_state, @@ -360,7 +353,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { webassembly::compile_with_config_with( &wasm_binary[..], CompilerConfig { - symbol_map: em_symbol_map, + symbol_map: em_symbol_map.clone(), track_state, ..Default::default() }, @@ -378,7 +371,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 load_cache_key = || -> Result<_, String> { + let mut 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| { @@ -406,7 +399,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { let module = webassembly::compile_with_config_with( &wasm_binary[..], CompilerConfig { - symbol_map: em_symbol_map, + symbol_map: em_symbol_map.clone(), track_state, ..Default::default() }, @@ -515,7 +508,9 @@ fn execute_wasm(options: &Run) -> Result<(), String> { #[cfg(any(feature = "backend-singlepass", feature = "backend-llvm"))] unsafe { if options.backend == Backend::Singlepass || options.backend == Backend::LLVM { - use wasmer_runtime_core::fault::{catch_unsafe_unwind, ensure_sighandler, with_ctx}; + use wasmer_runtime_core::fault::{ + catch_unsafe_unwind, ensure_sighandler, with_ctx, + }; use wasmer_runtime_core::state::{ x64::invoke_call_return_on_stack, InstanceImage, }; @@ -534,9 +529,9 @@ fn execute_wasm(options: &Run) -> Result<(), String> { } else { None }; - let breakpoints = instance.module.runnable_module.get_breakpoints(); loop { + let breakpoints = instance.module.runnable_module.get_breakpoints(); let ctx = instance.context_mut() as *mut _; let ret = with_ctx(ctx, || { if let Some(image) = image.take() { @@ -569,8 +564,35 @@ fn execute_wasm(options: &Run) -> Result<(), String> { image: Some(new_image.clone()), }); match op { - ShellExitOperation::ContinueWith(new_image) => { + ShellExitOperation::ContinueWith(new_image, new_backend) => { image = Some(new_image); + if let Some(new_backend) = new_backend { + let compiler = + match get_compiler_by_backend(new_backend) { + Some(x) => x, + None => { + return Err( + "the requested backend is not enabled" + .into(), + ) + } + }; + let module = webassembly::compile_with_config_with( + &wasm_binary[..], + CompilerConfig { + symbol_map: em_symbol_map.clone(), + track_state, + ..Default::default() + }, + &*compiler, + ) + .map_err(|e| { + format!("Can't compile module: {:?}", e) + })?; + instance = module.instantiate(&import_object).map_err( + |e| format!("Can't instantiate module: {:?}", e), + )?; + } } } } else { @@ -630,7 +652,7 @@ struct InteractiveShellContext { #[cfg(any(feature = "backend-singlepass", feature = "backend-llvm"))] #[derive(Debug)] enum ShellExitOperation { - ContinueWith(wasmer_runtime_core::state::InstanceImage), + ContinueWith(wasmer_runtime_core::state::InstanceImage, Option), } #[cfg(any(feature = "backend-singlepass", feature = "backend-llvm"))] @@ -683,7 +705,28 @@ fn interactive_shell(mut ctx: InteractiveShellContext) -> ShellExitOperation { } "continue" | "c" => { if let Some(image) = ctx.image.take() { - return ShellExitOperation::ContinueWith(image); + return ShellExitOperation::ContinueWith(image, None); + } else { + println!("Program state not available, cannot continue execution"); + } + } + "switch_backend" => { + let backend_name = parts.next(); + if backend_name.is_none() { + println!("Usage: switch_backend [backend_name]"); + continue; + } + let backend_name = backend_name.unwrap(); + let backend = match backend_name { + "singlepass" => Backend::Singlepass, + "llvm" => Backend::LLVM, + _ => { + println!("unknown backend"); + continue; + } + }; + if let Some(image) = ctx.image.take() { + return ShellExitOperation::ContinueWith(image, Some(backend)); } else { println!("Program state not available, cannot continue execution"); } @@ -752,6 +795,20 @@ fn validate(validate: Validate) { } } +fn get_compiler_by_backend(backend: Backend) -> Option> { + Some(match backend { + #[cfg(feature = "backend-singlepass")] + Backend::Singlepass => Box::new(SinglePassCompiler::new()), + #[cfg(not(feature = "backend-singlepass"))] + Backend::Singlepass => return None, + Backend::Cranelift => Box::new(CraneliftCompiler::new()), + #[cfg(feature = "backend-llvm")] + Backend::LLVM => Box::new(LLVMCompiler::new()), + #[cfg(not(feature = "backend-llvm"))] + Backend::LLVM => return None, + }) +} + fn main() { let options = CLIOptions::from_args(); match options { From 9ed5094f86feddd92e1b5bb1264b892ba7ca4bbb Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 1 Aug 2019 23:28:39 +0800 Subject: [PATCH 10/90] Resolve semantics for more values. --- lib/llvm-backend/src/backend.rs | 1 + lib/llvm-backend/src/code.rs | 89 +++++++++++++++++++++++- lib/llvm-backend/src/intrinsics.rs | 15 ++++- lib/llvm-backend/src/stackmap.rs | 104 +++++++++++++++++++++++++++++ lib/runtime-core/src/fault.rs | 2 + lib/runtime-core/src/lib.rs | 1 + lib/runtime-core/src/state.rs | 32 ++++++++- 7 files changed, 236 insertions(+), 8 deletions(-) diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index 058b91de04a..3bb9129eb70 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -367,6 +367,7 @@ impl LLVMBackend { .expect("size_record not found"); start_entry.populate_msm( + module_info, code_ptr as usize, &map, size_record, diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 9c11103e930..9d000961be5 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -19,7 +19,7 @@ use wasmer_runtime_core::{ module::{ModuleInfo, ModuleInner}, structures::{Map, TypedIndex}, types::{ - FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, SigIndex, TableIndex, Type, + FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, SigIndex, TableIndex, Type, ImportedFuncIndex, }, }; use wasmparser::{BinaryReaderError, MemoryImmediate, Operator, Type as WpType}; @@ -303,6 +303,7 @@ fn resolve_memory_ptr( } fn emit_stack_map( + module_info: &ModuleInfo, intrinsics: &Intrinsics, builder: &Builder, local_function_id: usize, @@ -310,6 +311,7 @@ fn emit_stack_map( kind: StackmapEntryKind, locals: &[PointerValue], state: &State, + ctx: &mut CtxType, opcode_offset: usize, ) { let stackmap_id = target.entries.len(); @@ -333,6 +335,76 @@ fn emit_stack_map( params.extend_from_slice(&state.stack); value_semantics.extend((0..state.stack.len()).map(ValueSemantic::WasmStack)); + params.push(ctx.basic()); + value_semantics.push(ValueSemantic::Ctx); + + if module_info.memories.len() + module_info.imported_memories.len() > 0 { + let cache = ctx.memory(MemoryIndex::new(0), intrinsics); + match cache { + MemoryCache::Dynamic { ptr_to_base_ptr, ptr_to_bounds } => { + params.push(ptr_to_base_ptr.as_basic_value_enum()); + value_semantics.push(ValueSemantic::PointerToMemoryBase); + + params.push(ptr_to_bounds.as_basic_value_enum()); + value_semantics.push(ValueSemantic::PointerToMemoryBound); + } + MemoryCache::Static { base_ptr, bounds } => { + params.push(base_ptr.as_basic_value_enum()); + value_semantics.push(ValueSemantic::MemoryBase); + + params.push(bounds.as_basic_value_enum()); + value_semantics.push(ValueSemantic::MemoryBound); + } + } + } + + if module_info.tables.len() + module_info.imported_tables.len() > 0 { + let (ptr_to_base_ptr, ptr_to_bounds) = ctx.table_prepare(TableIndex::new(0), intrinsics); + + params.push(ptr_to_base_ptr.as_basic_value_enum()); + value_semantics.push(ValueSemantic::PointerToTableBase); + + params.push(ptr_to_bounds.as_basic_value_enum()); + value_semantics.push(ValueSemantic::PointerToMemoryBound); + } + + if module_info.globals.len() + module_info.imported_globals.len() > 0 { + for i in 0..module_info.globals.len() + module_info.imported_globals.len() { + let cache = ctx.global_cache(GlobalIndex::new(i), intrinsics); + match cache { + GlobalCache::Const { value } => { + params.push(value); + value_semantics.push(ValueSemantic::Global(i)); + } + GlobalCache::Mut { ptr_to_value } => { + params.push(ptr_to_value.as_basic_value_enum()); + value_semantics.push(ValueSemantic::PointerToGlobal(i)); + } + } + + } + } + + if module_info.imported_functions.len() > 0 { + // TODO: Optimize this + for i in 0..module_info.imported_functions.len() { + let (func_ptr, ctx_ptr) = ctx.imported_func(ImportedFuncIndex::new(i), intrinsics); + + params.push(func_ptr.as_basic_value_enum()); + value_semantics.push(ValueSemantic::ImportedFuncPointer(i)); + + params.push(ctx_ptr.as_basic_value_enum()); + value_semantics.push(ValueSemantic::ImportedFuncCtx(i)); + } + } + + params.push(ctx.signal_mem().as_basic_value_enum()); + value_semantics.push(ValueSemantic::SignalMem); + + // TODO: sigindices + + assert_eq!(params.len(), value_semantics.len() + 2); + builder.build_call(intrinsics.experimental_stackmap, ¶ms, &state.var_name()); target.entries.push(StackmapEntry { @@ -487,6 +559,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let mut stackmaps = self.stackmaps.borrow_mut(); emit_stack_map( + &module_info, &intrinsics, &builder, self.index, @@ -494,6 +567,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { StackmapEntryKind::FunctionHeader, &self.locals, &state, + self.ctx.as_mut().unwrap(), ::std::usize::MAX, ); finalize_opcode_stack_map( @@ -605,6 +679,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { if let Some(offset) = opcode_offset { let mut stackmaps = self.stackmaps.borrow_mut(); emit_stack_map( + &info, intrinsics, builder, self.index, @@ -612,6 +687,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { StackmapEntryKind::Loop, &self.locals, state, + ctx, offset, ); let signal_mem = ctx.signal_mem(); @@ -892,6 +968,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { if let Some(offset) = opcode_offset { let mut stackmaps = self.stackmaps.borrow_mut(); emit_stack_map( + &info, intrinsics, builder, self.index, @@ -899,6 +976,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { StackmapEntryKind::Trappable, &self.locals, state, + ctx, offset, ); builder.build_call(intrinsics.trap, &[], "trap"); @@ -908,7 +986,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { self.index, &mut *stackmaps, StackmapEntryKind::Trappable, - offset + 1, + offset, ); } @@ -1052,6 +1130,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { if let Some(offset) = opcode_offset { let mut stackmaps = self.stackmaps.borrow_mut(); emit_stack_map( + &info, intrinsics, builder, self.index, @@ -1059,6 +1138,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { StackmapEntryKind::Call, &self.locals, state, + ctx, offset, ) } @@ -1241,6 +1321,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { if let Some(offset) = opcode_offset { let mut stackmaps = self.stackmaps.borrow_mut(); emit_stack_map( + &info, intrinsics, builder, self.index, @@ -1248,6 +1329,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { StackmapEntryKind::Call, &self.locals, state, + ctx, offset, ) } @@ -2737,6 +2819,7 @@ impl ModuleCodeGenerator if cfg!(test) { pass_manager.add_verifier_pass(); } + /* pass_manager.add_lower_expect_intrinsic_pass(); pass_manager.add_scalar_repl_aggregates_pass(); pass_manager.add_instruction_combining_pass(); @@ -2749,7 +2832,7 @@ impl ModuleCodeGenerator pass_manager.add_reassociate_pass(); pass_manager.add_cfg_simplification_pass(); pass_manager.add_bit_tracking_dce_pass(); - pass_manager.add_slp_vectorize_pass(); + pass_manager.add_slp_vectorize_pass();*/ pass_manager.run_on_module(&self.module); // self.module.print_to_stderr(); diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index 89d8f5fcd2f..e75486059bd 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -582,12 +582,11 @@ impl<'a> CtxType<'a> { }) } - pub fn table( + pub fn table_prepare( &mut self, index: TableIndex, intrinsics: &Intrinsics, - builder: &Builder, - ) -> (PointerValue, IntValue) { + ) -> (PointerValue, PointerValue) { let (cached_tables, info, ctx_ptr_value, cache_builder) = ( &mut self.cached_tables, self.info, @@ -646,6 +645,16 @@ impl<'a> CtxType<'a> { } }); + (ptr_to_base_ptr, ptr_to_bounds) + } + + pub fn table( + &mut self, + index: TableIndex, + intrinsics: &Intrinsics, + builder: &Builder, + ) -> (PointerValue, IntValue) { + let (ptr_to_base_ptr, ptr_to_bounds) = self.table_prepare(index, intrinsics); ( builder .build_load(ptr_to_base_ptr, "base_ptr") diff --git a/lib/llvm-backend/src/stackmap.rs b/lib/llvm-backend/src/stackmap.rs index 1a6ad7e20dc..86456b5518c 100644 --- a/lib/llvm-backend/src/stackmap.rs +++ b/lib/llvm-backend/src/stackmap.rs @@ -8,6 +8,13 @@ use wasmer_runtime_core::state::{ FunctionStateMap, MachineStateDiff, MachineValue, ModuleStateMap, OffsetInfo, RegisterIndex, SuspendOffset, WasmAbstractValue, }; +use wasmer_runtime_core::vm::Ctx; +use wasmer_runtime_core::{ + module::ModuleInfo, + types::{GlobalIndex, TableIndex, LocalOrImport}, + structures::TypedIndex, + vm, +}; #[derive(Default, Debug, Clone)] pub struct StackmapRegistry { @@ -29,6 +36,19 @@ pub struct StackmapEntry { pub enum ValueSemantic { WasmLocal(usize), WasmStack(usize), + Ctx, + SignalMem, + PointerToMemoryBase, + PointerToMemoryBound, // 64-bit + MemoryBase, + MemoryBound, // 64-bit + PointerToGlobal(usize), + Global(usize), + PointerToTableBase, + PointerToTableBound, + ImportedFuncPointer(usize), + ImportedFuncCtx(usize), + DynamicSigindice(usize), } #[derive(Debug, Clone, Copy, Eq, PartialEq)] @@ -69,6 +89,7 @@ pub struct MachineStateDiff { impl StackmapEntry { pub fn populate_msm( &self, + module_info: &ModuleInfo, code_addr: usize, llvm_map: &StackMap, size_record: &StkSizeRecord, @@ -86,6 +107,7 @@ impl StackmapEntry { .checked_sub(code_addr) .unwrap(); let target_offset = func_base_addr + map_record.instruction_offset as usize; + assert!(self.is_start); if msm.local_functions.len() == self.local_function_id { assert_eq!(self.kind, StackmapEntryKind::FunctionHeader); @@ -131,6 +153,31 @@ impl StackmapEntry { wasm_stack.push(WasmAbstractValue::Runtime); MachineValue::WasmStack(x) } + ValueSemantic::Ctx => MachineValue::Vmctx, + ValueSemantic::SignalMem => MachineValue::VmctxDeref(vec![Ctx::offset_interrupt_signal_mem() as usize, 0]), + ValueSemantic::PointerToMemoryBase => MachineValue::VmctxDeref(vec![Ctx::offset_memory_base() as usize]), + ValueSemantic::PointerToMemoryBound => MachineValue::VmctxDeref(vec![Ctx::offset_memory_bound() as usize]), + ValueSemantic::MemoryBase => MachineValue::VmctxDeref(vec![Ctx::offset_memory_base() as usize, 0]), + ValueSemantic::MemoryBound => MachineValue::VmctxDeref(vec![Ctx::offset_memory_bound() as usize, 0]), + ValueSemantic::PointerToGlobal(idx) => MachineValue::VmctxDeref(deref_global(module_info, idx, false)), + ValueSemantic::Global(idx) => MachineValue::VmctxDeref(deref_global(module_info, idx, true)), + ValueSemantic::PointerToTableBase => MachineValue::VmctxDeref(deref_table_base(module_info, 0, false)), + ValueSemantic::PointerToTableBound => MachineValue::VmctxDeref(deref_table_bound(module_info, 0, false)), + ValueSemantic::ImportedFuncPointer(idx) => MachineValue::VmctxDeref(vec![ + Ctx::offset_imported_funcs() as usize, + vm::ImportedFunc::size() as usize * idx + vm::ImportedFunc::offset_func() as usize, + 0, + ]), + ValueSemantic::ImportedFuncCtx(idx) => MachineValue::VmctxDeref(vec![ + Ctx::offset_imported_funcs() as usize, + vm::ImportedFunc::size() as usize * idx + vm::ImportedFunc::offset_vmctx() as usize, + 0, + ]), + ValueSemantic::DynamicSigindice(idx) => MachineValue::VmctxDeref(vec![ + Ctx::offset_signatures() as usize, + idx * 4, + 0, + ]), }; match loc.ty { LocationType::Register => { @@ -488,3 +535,60 @@ impl StackMap { Ok(map) } } + +fn deref_global(info: &ModuleInfo, idx: usize, deref_into_value: bool) -> Vec { + let mut x: Vec = match GlobalIndex::new(idx).local_or_import(info) { + LocalOrImport::Local(idx) => vec![ + Ctx::offset_globals() as usize, + idx.index() * 8, + 0, + ], + LocalOrImport::Import(idx) => vec![ + Ctx::offset_imported_globals() as usize, + idx.index() * 8, + 0, + ], + }; + if deref_into_value { + x.push(0); + } + x +} + +fn deref_table_base(info: &ModuleInfo, idx: usize, deref_into_value: bool) -> Vec { + let mut x: Vec = match TableIndex::new(idx).local_or_import(info) { + LocalOrImport::Local(idx) => vec![ + Ctx::offset_tables() as usize, + idx.index() * 8, + 0, + ], + LocalOrImport::Import(idx) => vec![ + Ctx::offset_imported_tables() as usize, + idx.index() * 8, + 0, + ], + }; + if deref_into_value { + x.push(0); + } + x +} + +fn deref_table_bound(info: &ModuleInfo, idx: usize, deref_into_value: bool) -> Vec { + let mut x: Vec = match TableIndex::new(idx).local_or_import(info) { + LocalOrImport::Local(idx) => vec![ + Ctx::offset_tables() as usize, + idx.index() * 8, + 8, + ], + LocalOrImport::Import(idx) => vec![ + Ctx::offset_imported_tables() as usize, + idx.index() * 8, + 8, + ], + }; + if deref_into_value { + x.push(0); + } + x +} \ No newline at end of file diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index 871b8f6facb..e5c7e2c7c5b 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -188,6 +188,8 @@ extern "C" fn signal_trap_handler( let should_unwind = allocate_and_run(TRAP_STACK_SIZE, || { let mut is_suspend_signal = false; + println!("SIGNAL: {:?} {:?}", Signal::from_c_int(signum), fault.faulting_addr); + match Signal::from_c_int(signum) { Ok(SIGTRAP) => { // breakpoint diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index 52b7cf82a85..a164f4727bf 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -1,5 +1,6 @@ #![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)] #![cfg_attr(nightly, feature(unwind_attributes))] +#![feature(core_intrinsics)] #[cfg(test)] #[macro_use] diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 81dcdbdcd7d..1acf0956a44 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -39,6 +39,7 @@ pub struct MachineStateDiff { pub enum MachineValue { Undefined, Vmctx, + VmctxDeref(Vec), PreserveRegister(RegisterIndex), CopyStackBPRelative(i32), // relative to Base Pointer, in byte offset ExplicitShadow, // indicates that all values above this are above the shadow region @@ -361,6 +362,14 @@ pub mod x64 { use crate::vm::Ctx; use std::any::Any; + unsafe fn compute_vmctx_deref(vmctx: *const Ctx, seq: &[usize]) -> u64 { + let mut ptr = &vmctx as *const *const Ctx as *const u8; + for x in seq { + ptr = (*(ptr as *const *const u8)).offset(*x as isize); + } + ptr as usize as u64 + } + pub fn new_machine_state() -> MachineState { MachineState { stack_values: vec![], @@ -427,6 +436,10 @@ pub mod x64 { stack_offset -= 1; stack[stack_offset] = vmctx as *mut Ctx as usize as u64; } + MachineValue::VmctxDeref(ref seq) => { + stack_offset -= 1; + stack[stack_offset] = compute_vmctx_deref(vmctx as *const Ctx, seq); + } MachineValue::PreserveRegister(index) => { stack_offset -= 1; stack[stack_offset] = known_registers[index.0].unwrap_or(0); @@ -481,7 +494,6 @@ pub mod x64 { } }, MachineValue::WasmLocal(x) => { - stack_offset -= 1; match fsm.locals[x] { WasmAbstractValue::Const(x) => { assert!(x <= ::std::u32::MAX as u64); @@ -494,6 +506,9 @@ pub mod x64 { } } } + MachineValue::VmctxDeref(ref seq) => { + stack[stack_offset] |= compute_vmctx_deref(vmctx as *const Ctx, seq) & (::std::u32::MAX as u64); + } MachineValue::Undefined => {} _ => unimplemented!("TwoHalves.0"), } @@ -510,7 +525,6 @@ pub mod x64 { } }, MachineValue::WasmLocal(x) => { - stack_offset -= 1; match fsm.locals[x] { WasmAbstractValue::Const(x) => { assert!(x <= ::std::u32::MAX as u64); @@ -523,6 +537,9 @@ pub mod x64 { } } } + MachineValue::VmctxDeref(ref seq) => { + stack[stack_offset] |= (compute_vmctx_deref(vmctx as *const Ctx, seq) & (::std::u32::MAX as u64)) << 32; + } MachineValue::Undefined => {} _ => unimplemented!("TwoHalves.1"), } @@ -539,6 +556,9 @@ pub mod x64 { MachineValue::Vmctx => { known_registers[i] = Some(vmctx as *mut Ctx as usize as u64); } + MachineValue::VmctxDeref(ref seq) => { + known_registers[i] = Some(compute_vmctx_deref(vmctx as *const Ctx, seq)); + } MachineValue::WasmStack(x) => match state.wasm_stack[x] { WasmAbstractValue::Const(x) => { known_registers[i] = Some(x); @@ -563,6 +583,7 @@ pub mod x64 { stack_offset -= 1; stack[stack_offset] = (code_base + activate_offset) as u64; // return address + println!("activating at {:?}", (code_base + activate_offset) as *const u8); } stack_offset -= 1; @@ -673,6 +694,7 @@ pub mod x64 { catch_unsafe_unwind( || { + ::std::intrinsics::breakpoint(); run_on_alternative_stack( stack.as_mut_ptr().offset(stack.len() as isize), stack.as_mut_ptr().offset(stack_offset as isize), @@ -765,6 +787,7 @@ pub mod x64 { match *v { MachineValue::Undefined => {} MachineValue::Vmctx => {} + MachineValue::VmctxDeref(_) => {} MachineValue::WasmStack(idx) => { if let Some(v) = known_registers[i] { wasm_stack[idx] = Some(v); @@ -809,6 +832,9 @@ pub mod x64 { MachineValue::Vmctx => { stack = stack.offset(1); } + MachineValue::VmctxDeref(_) => { + stack = stack.offset(1); + } MachineValue::PreserveRegister(idx) => { known_registers[idx.0] = Some(*stack); stack = stack.offset(1); @@ -834,6 +860,7 @@ pub mod x64 { MachineValue::WasmLocal(idx) => { wasm_locals[idx] = Some(v & 0xffffffffu64); } + MachineValue::VmctxDeref(_) => {} MachineValue::Undefined => {} _ => unimplemented!("TwoHalves.0 (read)"), } @@ -844,6 +871,7 @@ pub mod x64 { MachineValue::WasmLocal(idx) => { wasm_locals[idx] = Some(v >> 32); } + MachineValue::VmctxDeref(_) => {} MachineValue::Undefined => {} _ => unimplemented!("TwoHalves.1 (read)"), } From b50fd31adb4359223bd27b5b72f6f2368b36c831 Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 7 Aug 2019 00:06:35 +0800 Subject: [PATCH 11/90] Use setjmp/longjmp to handle LLVM exceptions. --- lib/llvm-backend/cpp/object_loader.cpp | 35 ++++++++++++++++++++++++++ lib/llvm-backend/cpp/object_loader.hh | 17 +++++++++---- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/lib/llvm-backend/cpp/object_loader.cpp b/lib/llvm-backend/cpp/object_loader.cpp index bf034a30875..f79b0316de2 100644 --- a/lib/llvm-backend/cpp/object_loader.cpp +++ b/lib/llvm-backend/cpp/object_loader.cpp @@ -5,6 +5,41 @@ extern "C" void __register_frame(uint8_t *); extern "C" void __deregister_frame(uint8_t *); +struct UnwindPoint { + UnwindPoint *prev; + jmp_buf unwind_info; + std::unique_ptr exception; +}; + +static thread_local UnwindPoint *unwind_state = nullptr; + +void catch_unwind(std::function&& f) { + UnwindPoint current; + current.prev = unwind_state; + unwind_state = ¤t; + + bool rethrow = false; + + if(setjmp(current.unwind_info)) { + rethrow = true; + } else { + f(); + } + + unwind_state = current.prev; + if(rethrow) throw *current.exception; +} + +void unsafe_unwind(std::exception *exception) { + UnwindPoint *state = unwind_state; + if(state) { + state->exception.reset(exception); + longjmp(state->unwind_info, 42); + } else { + abort(); + } +} + struct MemoryManager : llvm::RuntimeDyld::MemoryManager { public: MemoryManager(callbacks_t callbacks) : callbacks(callbacks) {} diff --git a/lib/llvm-backend/cpp/object_loader.hh b/lib/llvm-backend/cpp/object_loader.hh index 7a410b2dc07..045e3ed9136 100644 --- a/lib/llvm-backend/cpp/object_loader.hh +++ b/lib/llvm-backend/cpp/object_loader.hh @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include @@ -48,7 +50,10 @@ typedef struct { size_t data, vtable; } box_any_t; -struct WasmException { +void catch_unwind(std::function&& f); +[[noreturn]] void unsafe_unwind(std::exception *exception); + +struct WasmException : std::exception { public: virtual std::string description() const noexcept = 0; }; @@ -174,27 +179,29 @@ result_t module_load(const uint8_t *mem_ptr, size_t mem_size, return RESULT_OK; } -[[noreturn]] void throw_trap(WasmTrap::Type ty) { throw WasmTrap(ty); } +[[noreturn]] void throw_trap(WasmTrap::Type ty) { unsafe_unwind(new WasmTrap(ty)); } void module_delete(WasmModule *module) { delete module; } // Throw a fat pointer that's assumed to be `*mut dyn Any` on the rust // side. [[noreturn]] void throw_any(size_t data, size_t vtable) { - throw UserException(data, vtable); + unsafe_unwind(new UserException(data, vtable)); } // Throw a pointer that's assumed to be codegen::BreakpointHandler on the // rust side. [[noreturn]] void throw_breakpoint(uintptr_t callback) { - throw BreakpointException(callback); + unsafe_unwind(new BreakpointException(callback)); } bool invoke_trampoline(trampoline_t trampoline, void *ctx, void *func, void *params, void *results, WasmTrap::Type *trap_out, box_any_t *user_error, void *invoke_env) noexcept { try { - trampoline(ctx, func, params, results); + catch_unwind([trampoline, ctx, func, params, results]() { + trampoline(ctx, func, params, results); + }); return true; } catch (const WasmTrap &e) { *trap_out = e.type; From 4b1d337ebe5f6de2f30cea2e036f77356250767c Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 7 Aug 2019 00:38:42 +0800 Subject: [PATCH 12/90] Custom setjmp/longjmp to avoid SEH. (will it work?) --- lib/llvm-backend/build.rs | 2 ++ lib/llvm-backend/cpp/object_loader.cpp | 25 +++++++++++++----------- lib/llvm-backend/cpp/unwinding.s | 27 ++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 11 deletions(-) create mode 100644 lib/llvm-backend/cpp/unwinding.s diff --git a/lib/llvm-backend/build.rs b/lib/llvm-backend/build.rs index 6c8117dd9e3..904a83fb1d5 100644 --- a/lib/llvm-backend/build.rs +++ b/lib/llvm-backend/build.rs @@ -209,12 +209,14 @@ fn main() { cc::Build::new() .cpp(true) .file("cpp/object_loader.cpp") + .file("cpp/unwinding.s") .compile("llvm-backend"); println!("cargo:rustc-link-lib=static=llvm-backend"); println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=cpp/object_loader.cpp"); println!("cargo:rerun-if-changed=cpp/object_loader.hh"); + println!("cargo:rerun-if-changed=cpp/unwinding.s"); // Enable "nightly" cfg if the current compiler is nightly. if rustc_version::version_meta().unwrap().channel == rustc_version::Channel::Nightly { diff --git a/lib/llvm-backend/cpp/object_loader.cpp b/lib/llvm-backend/cpp/object_loader.cpp index f79b0316de2..ff2c4132b4d 100644 --- a/lib/llvm-backend/cpp/object_loader.cpp +++ b/lib/llvm-backend/cpp/object_loader.cpp @@ -4,37 +4,40 @@ extern "C" void __register_frame(uint8_t *); extern "C" void __deregister_frame(uint8_t *); +extern "C" void unwinding_setjmp(uint8_t **stack_out, void (*func)(void *), void *userdata); +[[noreturn]] extern "C" void unwinding_longjmp(uint8_t *stack_in); struct UnwindPoint { UnwindPoint *prev; - jmp_buf unwind_info; + uint8_t *stack; + std::function *f; std::unique_ptr exception; }; static thread_local UnwindPoint *unwind_state = nullptr; +static void unwind_payload(void *_point) { + UnwindPoint *point = (UnwindPoint *) _point; + (*point->f)(); +} + void catch_unwind(std::function&& f) { UnwindPoint current; current.prev = unwind_state; + current.f = &f; unwind_state = ¤t; - bool rethrow = false; - - if(setjmp(current.unwind_info)) { - rethrow = true; - } else { - f(); + unwinding_setjmp(¤t.stack, unwind_payload, (void *) ¤t); + if(current.exception) { + throw *current.exception; } - - unwind_state = current.prev; - if(rethrow) throw *current.exception; } void unsafe_unwind(std::exception *exception) { UnwindPoint *state = unwind_state; if(state) { state->exception.reset(exception); - longjmp(state->unwind_info, 42); + unwinding_longjmp(state->stack); } else { abort(); } diff --git a/lib/llvm-backend/cpp/unwinding.s b/lib/llvm-backend/cpp/unwinding.s new file mode 100644 index 00000000000..dfe91234eb0 --- /dev/null +++ b/lib/llvm-backend/cpp/unwinding.s @@ -0,0 +1,27 @@ +# (save_place, func(userdata), userdata) +.globl _unwinding_setjmp +_unwinding_setjmp: +push %r15 +push %r14 +push %r13 +push %r12 +push %rbx +push %rbp +sub $8, %rsp # 16-byte alignment +mov %rsp, (%rdi) +mov %rdx, %rdi +callq *%rsi +setjmp_ret: +add $8, %rsp +pop %rbp +pop %rbx +pop %r12 +pop %r13 +pop %r14 +pop %r15 +ret + +.globl _unwinding_longjmp +_unwinding_longjmp: +mov %rdi, %rsp +jmp setjmp_ret From b113f5a24bbb2b213b86b7af1f689b8f8d528fea Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 8 Aug 2019 03:19:19 +0800 Subject: [PATCH 13/90] longjmp turns out to work on Windows. Remove custom unwinding code. --- lib/llvm-backend/build.rs | 2 -- lib/llvm-backend/cpp/object_loader.cpp | 20 +++++++++++++++---- lib/llvm-backend/cpp/unwinding.s | 27 -------------------------- 3 files changed, 16 insertions(+), 33 deletions(-) delete mode 100644 lib/llvm-backend/cpp/unwinding.s diff --git a/lib/llvm-backend/build.rs b/lib/llvm-backend/build.rs index 904a83fb1d5..6c8117dd9e3 100644 --- a/lib/llvm-backend/build.rs +++ b/lib/llvm-backend/build.rs @@ -209,14 +209,12 @@ fn main() { cc::Build::new() .cpp(true) .file("cpp/object_loader.cpp") - .file("cpp/unwinding.s") .compile("llvm-backend"); println!("cargo:rustc-link-lib=static=llvm-backend"); println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=cpp/object_loader.cpp"); println!("cargo:rerun-if-changed=cpp/object_loader.hh"); - println!("cargo:rerun-if-changed=cpp/unwinding.s"); // Enable "nightly" cfg if the current compiler is nightly. if rustc_version::version_meta().unwrap().channel == rustc_version::Channel::Nightly { diff --git a/lib/llvm-backend/cpp/object_loader.cpp b/lib/llvm-backend/cpp/object_loader.cpp index ff2c4132b4d..224b498b740 100644 --- a/lib/llvm-backend/cpp/object_loader.cpp +++ b/lib/llvm-backend/cpp/object_loader.cpp @@ -1,15 +1,27 @@ #include "object_loader.hh" #include #include +#include extern "C" void __register_frame(uint8_t *); extern "C" void __deregister_frame(uint8_t *); -extern "C" void unwinding_setjmp(uint8_t **stack_out, void (*func)(void *), void *userdata); -[[noreturn]] extern "C" void unwinding_longjmp(uint8_t *stack_in); + +void unwinding_setjmp(jmp_buf stack_out, void (*func)(void *), void *userdata) { + if(setjmp(stack_out)) { + + } else { + func(userdata); + } +} + +[[noreturn]] +void unwinding_longjmp(jmp_buf stack_in) { + longjmp(stack_in, 42); +} struct UnwindPoint { UnwindPoint *prev; - uint8_t *stack; + jmp_buf stack; std::function *f; std::unique_ptr exception; }; @@ -27,7 +39,7 @@ void catch_unwind(std::function&& f) { current.f = &f; unwind_state = ¤t; - unwinding_setjmp(¤t.stack, unwind_payload, (void *) ¤t); + unwinding_setjmp(current.stack, unwind_payload, (void *) ¤t); if(current.exception) { throw *current.exception; } diff --git a/lib/llvm-backend/cpp/unwinding.s b/lib/llvm-backend/cpp/unwinding.s deleted file mode 100644 index dfe91234eb0..00000000000 --- a/lib/llvm-backend/cpp/unwinding.s +++ /dev/null @@ -1,27 +0,0 @@ -# (save_place, func(userdata), userdata) -.globl _unwinding_setjmp -_unwinding_setjmp: -push %r15 -push %r14 -push %r13 -push %r12 -push %rbx -push %rbp -sub $8, %rsp # 16-byte alignment -mov %rsp, (%rdi) -mov %rdx, %rdi -callq *%rsi -setjmp_ret: -add $8, %rsp -pop %rbp -pop %rbx -pop %r12 -pop %r13 -pop %r14 -pop %r15 -ret - -.globl _unwinding_longjmp -_unwinding_longjmp: -mov %rdi, %rsp -jmp setjmp_ret From 0d604b754b3233d402448daf87465c358906c877 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 8 Aug 2019 21:54:39 +0800 Subject: [PATCH 14/90] Commented out code for saving semantics of internal values. --- lib/llvm-backend/src/code.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 9d000961be5..2344d1991ba 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -335,6 +335,10 @@ fn emit_stack_map( params.extend_from_slice(&state.stack); value_semantics.extend((0..state.stack.len()).map(ValueSemantic::WasmStack)); + // FIXME: Information below is needed for Abstract -> Runtime state transform. + // Commented out to accelerate compilation and reduce memory usage. + // Check this again when we support "full" LLVM OSR. + /* params.push(ctx.basic()); value_semantics.push(ValueSemantic::Ctx); @@ -402,6 +406,7 @@ fn emit_stack_map( value_semantics.push(ValueSemantic::SignalMem); // TODO: sigindices + */ assert_eq!(params.len(), value_semantics.len() + 2); From c1619026d52e3a2acd1f35a421890698c4f2a2ef Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 9 Aug 2019 04:26:17 +0800 Subject: [PATCH 15/90] Swap code lazily when tiering up from singlepass to LLVM. Does not handle long-running functions, but should work at least. --- lib/llvm-backend/src/backend.rs | 19 +++ lib/llvm-backend/src/code.rs | 6 +- lib/llvm-backend/src/stackmap.rs | 96 +++++++------- lib/runtime-core/src/backend.rs | 9 ++ lib/runtime-core/src/fault.rs | 24 +++- lib/runtime-core/src/loader.rs | 17 ++- lib/runtime-core/src/state.rs | 55 ++++---- lib/singlepass-backend/src/codegen_x64.rs | 58 +++++++- lib/singlepass-backend/src/emitter_x64.rs | 6 + src/bin/wasmer.rs | 154 +++++++++++++++++++++- 10 files changed, 350 insertions(+), 94 deletions(-) diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index 3bb9129eb70..f1d3f347a70 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -239,6 +239,7 @@ pub struct LLVMBackend { #[allow(dead_code)] buffer: Arc, msm: Option, + local_func_id_to_offset: Vec, } impl LLVMBackend { @@ -380,6 +381,17 @@ impl LLVMBackend { } } + let code_ptr = unsafe { llvm_backend_get_code_ptr(module) } as usize; + let code_len = unsafe { llvm_backend_get_code_size(module) } as usize; + + let local_func_id_to_offset: Vec = local_func_id_to_addr + .iter() + .map(|&x| { + assert!(x >= code_ptr && x < code_ptr + code_len); + x - code_ptr + }) + .collect(); + //println!("MSM: {:?}", msm); ( @@ -387,6 +399,7 @@ impl LLVMBackend { module, buffer: Arc::clone(&buffer), msm: Some(msm), + local_func_id_to_offset, }, LLVMCache { buffer }, ) @@ -397,6 +410,7 @@ impl LLVMBackend { module, buffer: Arc::clone(&buffer), msm: None, + local_func_id_to_offset: vec![], }, LLVMCache { buffer }, ) @@ -428,6 +442,7 @@ impl LLVMBackend { module, buffer: Arc::clone(&buffer), msm: None, + local_func_id_to_offset: vec![], }, LLVMCache { buffer }, )) @@ -491,6 +506,10 @@ impl RunnableModule for LLVMBackend { }) } + fn get_local_function_offsets(&self) -> Option> { + Some(self.local_func_id_to_offset.clone()) + } + fn get_module_state_map(&self) -> Option { self.msm.clone() } diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 2344d1991ba..dea3d101204 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -19,7 +19,7 @@ use wasmer_runtime_core::{ module::{ModuleInfo, ModuleInner}, structures::{Map, TypedIndex}, types::{ - FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, SigIndex, TableIndex, Type, ImportedFuncIndex, + FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, SigIndex, TableIndex, Type, }, }; use wasmparser::{BinaryReaderError, MemoryImmediate, Operator, Type as WpType}; @@ -303,7 +303,7 @@ fn resolve_memory_ptr( } fn emit_stack_map( - module_info: &ModuleInfo, + _module_info: &ModuleInfo, intrinsics: &Intrinsics, builder: &Builder, local_function_id: usize, @@ -311,7 +311,7 @@ fn emit_stack_map( kind: StackmapEntryKind, locals: &[PointerValue], state: &State, - ctx: &mut CtxType, + _ctx: &mut CtxType, opcode_offset: usize, ) { let stackmap_id = target.entries.len(); diff --git a/lib/llvm-backend/src/stackmap.rs b/lib/llvm-backend/src/stackmap.rs index 86456b5518c..b08da885816 100644 --- a/lib/llvm-backend/src/stackmap.rs +++ b/lib/llvm-backend/src/stackmap.rs @@ -11,8 +11,8 @@ use wasmer_runtime_core::state::{ use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::{ module::ModuleInfo, - types::{GlobalIndex, TableIndex, LocalOrImport}, structures::TypedIndex, + types::{GlobalIndex, LocalOrImport, TableIndex}, vm, }; @@ -154,30 +154,48 @@ impl StackmapEntry { MachineValue::WasmStack(x) } ValueSemantic::Ctx => MachineValue::Vmctx, - ValueSemantic::SignalMem => MachineValue::VmctxDeref(vec![Ctx::offset_interrupt_signal_mem() as usize, 0]), - ValueSemantic::PointerToMemoryBase => MachineValue::VmctxDeref(vec![Ctx::offset_memory_base() as usize]), - ValueSemantic::PointerToMemoryBound => MachineValue::VmctxDeref(vec![Ctx::offset_memory_bound() as usize]), - ValueSemantic::MemoryBase => MachineValue::VmctxDeref(vec![Ctx::offset_memory_base() as usize, 0]), - ValueSemantic::MemoryBound => MachineValue::VmctxDeref(vec![Ctx::offset_memory_bound() as usize, 0]), - ValueSemantic::PointerToGlobal(idx) => MachineValue::VmctxDeref(deref_global(module_info, idx, false)), - ValueSemantic::Global(idx) => MachineValue::VmctxDeref(deref_global(module_info, idx, true)), - ValueSemantic::PointerToTableBase => MachineValue::VmctxDeref(deref_table_base(module_info, 0, false)), - ValueSemantic::PointerToTableBound => MachineValue::VmctxDeref(deref_table_bound(module_info, 0, false)), + ValueSemantic::SignalMem => { + MachineValue::VmctxDeref(vec![Ctx::offset_interrupt_signal_mem() as usize, 0]) + } + ValueSemantic::PointerToMemoryBase => { + MachineValue::VmctxDeref(vec![Ctx::offset_memory_base() as usize]) + } + ValueSemantic::PointerToMemoryBound => { + MachineValue::VmctxDeref(vec![Ctx::offset_memory_bound() as usize]) + } + ValueSemantic::MemoryBase => { + MachineValue::VmctxDeref(vec![Ctx::offset_memory_base() as usize, 0]) + } + ValueSemantic::MemoryBound => { + MachineValue::VmctxDeref(vec![Ctx::offset_memory_bound() as usize, 0]) + } + ValueSemantic::PointerToGlobal(idx) => { + MachineValue::VmctxDeref(deref_global(module_info, idx, false)) + } + ValueSemantic::Global(idx) => { + MachineValue::VmctxDeref(deref_global(module_info, idx, true)) + } + ValueSemantic::PointerToTableBase => { + MachineValue::VmctxDeref(deref_table_base(module_info, 0, false)) + } + ValueSemantic::PointerToTableBound => { + MachineValue::VmctxDeref(deref_table_bound(module_info, 0, false)) + } ValueSemantic::ImportedFuncPointer(idx) => MachineValue::VmctxDeref(vec![ Ctx::offset_imported_funcs() as usize, - vm::ImportedFunc::size() as usize * idx + vm::ImportedFunc::offset_func() as usize, + vm::ImportedFunc::size() as usize * idx + + vm::ImportedFunc::offset_func() as usize, 0, ]), ValueSemantic::ImportedFuncCtx(idx) => MachineValue::VmctxDeref(vec![ Ctx::offset_imported_funcs() as usize, - vm::ImportedFunc::size() as usize * idx + vm::ImportedFunc::offset_vmctx() as usize, - 0, - ]), - ValueSemantic::DynamicSigindice(idx) => MachineValue::VmctxDeref(vec![ - Ctx::offset_signatures() as usize, - idx * 4, + vm::ImportedFunc::size() as usize * idx + + vm::ImportedFunc::offset_vmctx() as usize, 0, ]), + ValueSemantic::DynamicSigindice(idx) => { + MachineValue::VmctxDeref(vec![Ctx::offset_signatures() as usize, idx * 4, 0]) + } }; match loc.ty { LocationType::Register => { @@ -538,16 +556,10 @@ impl StackMap { fn deref_global(info: &ModuleInfo, idx: usize, deref_into_value: bool) -> Vec { let mut x: Vec = match GlobalIndex::new(idx).local_or_import(info) { - LocalOrImport::Local(idx) => vec![ - Ctx::offset_globals() as usize, - idx.index() * 8, - 0, - ], - LocalOrImport::Import(idx) => vec![ - Ctx::offset_imported_globals() as usize, - idx.index() * 8, - 0, - ], + LocalOrImport::Local(idx) => vec![Ctx::offset_globals() as usize, idx.index() * 8, 0], + LocalOrImport::Import(idx) => { + vec![Ctx::offset_imported_globals() as usize, idx.index() * 8, 0] + } }; if deref_into_value { x.push(0); @@ -557,16 +569,10 @@ fn deref_global(info: &ModuleInfo, idx: usize, deref_into_value: bool) -> Vec Vec { let mut x: Vec = match TableIndex::new(idx).local_or_import(info) { - LocalOrImport::Local(idx) => vec![ - Ctx::offset_tables() as usize, - idx.index() * 8, - 0, - ], - LocalOrImport::Import(idx) => vec![ - Ctx::offset_imported_tables() as usize, - idx.index() * 8, - 0, - ], + LocalOrImport::Local(idx) => vec![Ctx::offset_tables() as usize, idx.index() * 8, 0], + LocalOrImport::Import(idx) => { + vec![Ctx::offset_imported_tables() as usize, idx.index() * 8, 0] + } }; if deref_into_value { x.push(0); @@ -576,19 +582,13 @@ fn deref_table_base(info: &ModuleInfo, idx: usize, deref_into_value: bool) -> Ve fn deref_table_bound(info: &ModuleInfo, idx: usize, deref_into_value: bool) -> Vec { let mut x: Vec = match TableIndex::new(idx).local_or_import(info) { - LocalOrImport::Local(idx) => vec![ - Ctx::offset_tables() as usize, - idx.index() * 8, - 8, - ], - LocalOrImport::Import(idx) => vec![ - Ctx::offset_imported_tables() as usize, - idx.index() * 8, - 8, - ], + LocalOrImport::Local(idx) => vec![Ctx::offset_tables() as usize, idx.index() * 8, 8], + LocalOrImport::Import(idx) => { + vec![Ctx::offset_imported_tables() as usize, idx.index() * 8, 8] + } }; if deref_into_value { x.push(0); } x -} \ No newline at end of file +} diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs index 1eb8ba108a9..68533659cc4 100644 --- a/lib/runtime-core/src/backend.rs +++ b/lib/runtime-core/src/backend.rs @@ -151,6 +151,10 @@ pub trait RunnableModule: Send + Sync { None } + unsafe fn patch_local_function(&self, _idx: usize, _target_address: usize) -> bool { + false + } + /// A wasm trampoline contains the necessary data to dynamically call an exported wasm function. /// Given a particular signature index, we are returned a trampoline that is matched with that /// signature and an invoke function that can call the trampoline. @@ -167,6 +171,11 @@ pub trait RunnableModule: Send + Sync { fn get_offsets(&self) -> Option> { None } + + /// Returns the beginning offsets of all local functions. + fn get_local_function_offsets(&self) -> Option> { + None + } } pub trait CacheGen: Send + Sync { diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index e5c7e2c7c5b..0fde80daf20 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -17,7 +17,7 @@ use nix::sys::signal::{ SIGSEGV, SIGTRAP, }; use std::any::Any; -use std::cell::UnsafeCell; +use std::cell::{Cell, UnsafeCell}; use std::ffi::c_void; use std::process; use std::sync::atomic::{AtomicBool, Ordering}; @@ -41,6 +41,7 @@ struct UnwindInfo { thread_local! { static UNWIND: UnsafeCell> = UnsafeCell::new(None); static CURRENT_CTX: UnsafeCell<*mut vm::Ctx> = UnsafeCell::new(::std::ptr::null_mut()); + static WAS_SIGINT_TRIGGERED: Cell = Cell::new(false); } struct InterruptSignalMem(*mut u8); @@ -69,6 +70,10 @@ lazy_static! { } static INTERRUPT_SIGNAL_DELIVERED: AtomicBool = AtomicBool::new(false); +pub fn was_sigint_triggered_fault() -> bool { + WAS_SIGINT_TRIGGERED.with(|x| x.get()) +} + pub unsafe fn with_ctx R>(ctx: *mut vm::Ctx, cb: F) -> R { let addr = CURRENT_CTX.with(|x| x.get()); let old = *addr; @@ -82,6 +87,17 @@ pub unsafe fn get_wasm_interrupt_signal_mem() -> *mut u8 { INTERRUPT_SIGNAL_MEM.0 } +pub unsafe fn set_wasm_interrupt_on_ctx(ctx: *mut vm::Ctx) { + if mprotect( + (&*ctx).internal.interrupt_signal_mem as _, + INTERRUPT_SIGNAL_MEM_SIZE, + PROT_NONE, + ) < 0 + { + panic!("cannot set PROT_NONE on signal mem"); + } +} + 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 { @@ -188,7 +204,7 @@ extern "C" fn signal_trap_handler( let should_unwind = allocate_and_run(TRAP_STACK_SIZE, || { let mut is_suspend_signal = false; - println!("SIGNAL: {:?} {:?}", Signal::from_c_int(signum), fault.faulting_addr); + WAS_SIGINT_TRIGGERED.with(|x| x.set(false)); match Signal::from_c_int(signum) { Ok(SIGTRAP) => { @@ -215,7 +231,9 @@ extern "C" fn signal_trap_handler( if fault.faulting_addr as usize == get_wasm_interrupt_signal_mem() as usize { is_suspend_signal = true; clear_wasm_interrupt(); - INTERRUPT_SIGNAL_DELIVERED.store(false, Ordering::SeqCst); + if INTERRUPT_SIGNAL_DELIVERED.swap(false, Ordering::SeqCst) { + WAS_SIGINT_TRIGGERED.with(|x| x.set(true)); + } } } _ => {} diff --git a/lib/runtime-core/src/loader.rs b/lib/runtime-core/src/loader.rs index 5ef127ec728..2c71addff03 100644 --- a/lib/runtime-core/src/loader.rs +++ b/lib/runtime-core/src/loader.rs @@ -102,13 +102,20 @@ pub struct CodeMemory { size: usize, } +unsafe impl Send for CodeMemory {} +unsafe impl Sync for CodeMemory {} + #[cfg(not(unix))] impl CodeMemory { pub fn new(_size: usize) -> CodeMemory { unimplemented!(); } - pub fn make_executable(&mut self) { + pub fn make_executable(&self) { + unimplemented!(); + } + + pub fn make_writable(&self) { unimplemented!(); } } @@ -139,11 +146,17 @@ impl CodeMemory { } } - pub fn make_executable(&mut self) { + 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"); } } + + 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"); + } + } } #[cfg(unix)] diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 1acf0956a44..e33d2d11d22 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -493,21 +493,21 @@ pub mod x64 { stack[stack_offset] |= v; } }, - MachineValue::WasmLocal(x) => { - match fsm.locals[x] { - WasmAbstractValue::Const(x) => { - assert!(x <= ::std::u32::MAX as u64); - stack[stack_offset] |= x; - } - WasmAbstractValue::Runtime => { - let v = f.locals[x].unwrap(); - assert!(v <= ::std::u32::MAX as u64); - stack[stack_offset] |= v; - } + MachineValue::WasmLocal(x) => match fsm.locals[x] { + WasmAbstractValue::Const(x) => { + assert!(x <= ::std::u32::MAX as u64); + stack[stack_offset] |= x; } - } + WasmAbstractValue::Runtime => { + let v = f.locals[x].unwrap(); + assert!(v <= ::std::u32::MAX as u64); + stack[stack_offset] |= v; + } + }, MachineValue::VmctxDeref(ref seq) => { - stack[stack_offset] |= compute_vmctx_deref(vmctx as *const Ctx, seq) & (::std::u32::MAX as u64); + stack[stack_offset] |= + compute_vmctx_deref(vmctx as *const Ctx, seq) + & (::std::u32::MAX as u64); } MachineValue::Undefined => {} _ => unimplemented!("TwoHalves.0"), @@ -524,21 +524,22 @@ pub mod x64 { stack[stack_offset] |= v << 32; } }, - MachineValue::WasmLocal(x) => { - match fsm.locals[x] { - WasmAbstractValue::Const(x) => { - assert!(x <= ::std::u32::MAX as u64); - stack[stack_offset] |= x << 32; - } - WasmAbstractValue::Runtime => { - let v = f.locals[x].unwrap(); - assert!(v <= ::std::u32::MAX as u64); - stack[stack_offset] |= v << 32; - } + MachineValue::WasmLocal(x) => match fsm.locals[x] { + WasmAbstractValue::Const(x) => { + assert!(x <= ::std::u32::MAX as u64); + stack[stack_offset] |= x << 32; } - } + WasmAbstractValue::Runtime => { + let v = f.locals[x].unwrap(); + assert!(v <= ::std::u32::MAX as u64); + stack[stack_offset] |= v << 32; + } + }, MachineValue::VmctxDeref(ref seq) => { - stack[stack_offset] |= (compute_vmctx_deref(vmctx as *const Ctx, seq) & (::std::u32::MAX as u64)) << 32; + stack[stack_offset] |= + (compute_vmctx_deref(vmctx as *const Ctx, seq) + & (::std::u32::MAX as u64)) + << 32; } MachineValue::Undefined => {} _ => unimplemented!("TwoHalves.1"), @@ -583,7 +584,6 @@ pub mod x64 { stack_offset -= 1; stack[stack_offset] = (code_base + activate_offset) as u64; // return address - println!("activating at {:?}", (code_base + activate_offset) as *const u8); } stack_offset -= 1; @@ -694,7 +694,6 @@ pub mod x64 { catch_unsafe_unwind( || { - ::std::intrinsics::breakpoint(); run_on_alternative_stack( stack.as_mut_ptr().offset(stack.len() as isize), stack.as_mut_ptr().offset(stack_offset as isize), diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index afd358cc2b6..081b067a913 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -20,6 +20,7 @@ use wasmer_runtime_core::{ }, cache::{Artifact, Error as CacheError}, codegen::*, + loader::CodeMemory, memory::MemoryType, module::{ModuleInfo, ModuleInner}, state::{ @@ -172,7 +173,7 @@ unsafe impl Sync for FuncPtr {} pub struct X64ExecutionContext { #[allow(dead_code)] - code: ExecutableBuffer, + code: CodeMemory, #[allow(dead_code)] functions: Vec, function_pointers: Vec, @@ -220,6 +221,30 @@ impl RunnableModule for X64ExecutionContext { Some(self.breakpoints.clone()) } + unsafe fn patch_local_function(&self, idx: usize, target_address: usize) -> bool { + // movabsq ?, %rax; + // jmpq *%rax; + #[repr(packed)] + struct Trampoline { + movabsq: [u8; 2], + addr: u64, + jmpq: [u8; 2], + } + + self.code.make_writable(); + + let trampoline = &mut *(self.function_pointers[self.func_import_count + idx].0 + as *const Trampoline as *mut Trampoline); + trampoline.movabsq[0] = 0x48; + trampoline.movabsq[1] = 0xb8; + trampoline.addr = target_address as u64; + trampoline.jmpq[0] = 0xff; + trampoline.jmpq[1] = 0xe0; + + self.code.make_executable(); + true + } + fn get_trampoline(&self, _: &ModuleInfo, sig_index: SigIndex) -> Option { use std::ffi::c_void; use wasmer_runtime_core::typed_func::WasmTrapInfo; @@ -306,6 +331,15 @@ impl RunnableModule for X64ExecutionContext { fn get_offsets(&self) -> Option> { Some(self.function_offsets.iter().map(|x| x.0).collect()) } + + fn get_local_function_offsets(&self) -> Option> { + Some( + self.function_offsets[self.func_import_count..] + .iter() + .map(|x| x.0) + .collect(), + ) + } } #[derive(Debug)] @@ -413,7 +447,10 @@ impl ModuleCodeGenerator } }; let total_size = assembler.get_offset().0; - let output = assembler.finalize().unwrap(); + let _output = assembler.finalize().unwrap(); + let mut output = CodeMemory::new(_output.len()); + output[0.._output.len()].copy_from_slice(&_output); + output.make_executable(); let function_labels = if let Some(x) = self.functions.last() { x.function_labels.as_ref().unwrap() @@ -440,14 +477,21 @@ impl ModuleCodeGenerator }); } }; - out_labels.push(FuncPtr(output.ptr(*offset) as _)); + out_labels.push(FuncPtr( + unsafe { output.as_ptr().offset(offset.0 as isize) } as _, + )); out_offsets.push(*offset); } let breakpoints: Arc> = Arc::new( breakpoints .into_iter() - .map(|(offset, f)| (output.ptr(offset) as usize, f)) + .map(|(offset, f)| { + ( + unsafe { output.as_ptr().offset(offset.0 as isize) } as usize, + f, + ) + }) .collect(), ); @@ -1634,6 +1678,12 @@ impl FunctionCodeGenerator for X64FunctionCode { fn begin_body(&mut self, _module_info: &ModuleInfo) -> Result<(), CodegenError> { let a = self.assembler.as_mut().unwrap(); + let start_label = a.get_label(); + // patchpoint of 16 bytes + for _ in 0..16 { + a.emit_nop(); + } + a.emit_label(start_label); a.emit_push(Size::S64, Location::GPR(GPR::RBP)); a.emit_mov(Size::S64, Location::GPR(GPR::RSP), Location::GPR(GPR::RBP)); diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index 0fc7795ff20..235c3894fbe 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -60,6 +60,8 @@ pub trait Emitter { fn emit_label(&mut self, label: Self::Label); + fn emit_nop(&mut self); + fn emit_mov(&mut self, sz: Size, src: Location, dst: Location); fn emit_lea(&mut self, sz: Size, src: Location, dst: Location); fn emit_lea_label(&mut self, label: Self::Label, dst: Location); @@ -467,6 +469,10 @@ impl Emitter for Assembler { dynasm!(self ; => label); } + fn emit_nop(&mut self) { + dynasm!(self ; nop); + } + fn emit_mov(&mut self, sz: Size, src: Location, dst: Location) { binop_all_nofp!(mov, self, sz, src, dst, { binop_imm64_gpr!(mov, self, sz, src, dst, { diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 8ad45f9f1e2..f9cb7c5f94b 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -9,6 +9,7 @@ use std::io::Read; use std::path::PathBuf; use std::process::exit; use std::str::FromStr; +use std::sync::{Arc, Mutex}; use hashbrown::HashMap; use structopt::StructOpt; @@ -25,7 +26,9 @@ use wasmer_runtime_core::{ self, backend::{Backend, Compiler, CompilerConfig, MemoryBoundCheckMode}, debug, + fault::{set_wasm_interrupt_on_ctx, was_sigint_triggered_fault}, loader::{Instance as LoadedInstance, LocalLoader}, + Instance, Module, }; #[cfg(feature = "backend-singlepass")] use wasmer_singlepass_backend::SinglePassCompiler; @@ -113,7 +116,7 @@ struct Run { loader: Option, /// Path to previously saved instance image to resume. - #[cfg(any(feature = "backend-singlepass", feature = "backend-llvm"))] + #[cfg(feature = "managed")] #[structopt(long = "resume")] resume: Option, @@ -187,6 +190,55 @@ struct Validate { path: PathBuf, } +struct OptimizationState { + outcome: Mutex>, +} + +struct OptimizationOutcome { + module: Module, +} + +struct Defer(Option); +impl Drop for Defer { + fn drop(&mut self) { + if let Some(f) = self.0.take() { + f(); + } + } +} + +#[repr(transparent)] +struct CtxWrapper(*mut wasmer_runtime_core::vm::Ctx); +unsafe impl Send for CtxWrapper {} +unsafe impl Sync for CtxWrapper {} + +#[cfg(feature = "managed")] +unsafe fn begin_optimize( + binary: Vec, + compiler: Box, + ctx: Arc>, + state: Arc, +) { + let module = match webassembly::compile_with_config_with( + &binary[..], + CompilerConfig { + symbol_map: None, + track_state: true, + ..Default::default() + }, + &*compiler, + ) { + Ok(x) => x, + Err(_) => return, + }; + + let ctx_inner = ctx.lock().unwrap(); + if !ctx_inner.0.is_null() { + *state.outcome.lock().unwrap() = Some(OptimizationOutcome { module }); + set_wasm_interrupt_on_ctx(ctx_inner.0); + } +} + /// Read the contents of a file fn read_file_contents(path: &PathBuf) -> Result, io::Error> { let mut buffer: Vec = Vec::new(); @@ -505,9 +557,9 @@ fn execute_wasm(options: &Run) -> Result<(), String> { let start: Func<(), ()> = instance.func("_start").map_err(|e| format!("{:?}", e))?; - #[cfg(any(feature = "backend-singlepass", feature = "backend-llvm"))] + #[cfg(feature = "managed")] unsafe { - if options.backend == Backend::Singlepass || options.backend == Backend::LLVM { + if options.backend == Backend::Singlepass { use wasmer_runtime_core::fault::{ catch_unsafe_unwind, ensure_sighandler, with_ctx, }; @@ -530,7 +582,86 @@ fn execute_wasm(options: &Run) -> Result<(), String> { None }; + let ctx_box = + Arc::new(Mutex::new(CtxWrapper(instance.context_mut() as *mut _))); + // Ensure that the ctx pointer's lifetime is not longer than Instance's. + let _deferred_ctx_box_cleanup: Defer<_> = { + let ctx_box = ctx_box.clone(); + Defer(Some(move || { + ctx_box.lock().unwrap().0 = ::std::ptr::null_mut(); + })) + }; + let opt_state = Arc::new(OptimizationState { + outcome: Mutex::new(None), + }); + + { + let wasm_binary = wasm_binary.to_vec(); + let ctx_box = ctx_box.clone(); + let opt_state = opt_state.clone(); + ::std::thread::spawn(move || { + // TODO: CLI option for optimized backend + begin_optimize( + wasm_binary, + get_compiler_by_backend(Backend::LLVM).unwrap(), + ctx_box, + opt_state, + ); + }); + } + + let mut patched = false; + let mut optimized_instance: Option = None; + loop { + let optimized: Option<&mut Instance> = + if let Some(ref mut x) = optimized_instance { + Some(x) + } else { + let mut outcome = opt_state.outcome.lock().unwrap(); + if let Some(x) = outcome.take() { + let instance = + x.module.instantiate(&import_object).map_err(|e| { + format!("Can't instantiate module: {:?}", e) + })?; + optimized_instance = Some(instance); + optimized_instance.as_mut() + } else { + None + } + }; + if !patched && false { + if let Some(optimized) = optimized { + let base = module.info().imported_functions.len(); + let code_ptr = optimized + .module + .runnable_module + .get_code() + .unwrap() + .as_ptr() + as usize; + let target_addresses: Vec = optimized + .module + .runnable_module + .get_local_function_offsets() + .unwrap() + .into_iter() + .map(|x| code_ptr + x) + .collect(); + assert_eq!( + target_addresses.len(), + module.info().func_assoc.len() - base + ); + for i in base..module.info().func_assoc.len() { + instance + .module + .runnable_module + .patch_local_function(i - base, target_addresses[i - base]); + } + patched = true; + eprintln!("Patched"); + } + } let breakpoints = instance.module.runnable_module.get_breakpoints(); let ctx = instance.context_mut() as *mut _; let ret = with_ctx(ctx, || { @@ -560,6 +691,14 @@ fn execute_wasm(options: &Run) -> Result<(), String> { }); if let Err(e) = ret { if let Some(new_image) = e.downcast_ref::() { + // Tier switch event + if !was_sigint_triggered_fault() + && optimized_instance.is_none() + && opt_state.outcome.lock().unwrap().is_some() + { + image = Some(new_image.clone()); + continue; + } let op = interactive_shell(InteractiveShellContext { image: Some(new_image.clone()), }); @@ -644,18 +783,18 @@ fn execute_wasm(options: &Run) -> Result<(), String> { Ok(()) } -#[cfg(any(feature = "backend-singlepass", feature = "backend-llvm"))] +#[cfg(feature = "managed")] struct InteractiveShellContext { image: Option, } -#[cfg(any(feature = "backend-singlepass", feature = "backend-llvm"))] +#[cfg(feature = "managed")] #[derive(Debug)] enum ShellExitOperation { ContinueWith(wasmer_runtime_core::state::InstanceImage, Option), } -#[cfg(any(feature = "backend-singlepass", feature = "backend-llvm"))] +#[cfg(feature = "managed")] fn interactive_shell(mut ctx: InteractiveShellContext) -> ShellExitOperation { use std::io::Write; @@ -710,6 +849,8 @@ fn interactive_shell(mut ctx: InteractiveShellContext) -> ShellExitOperation { println!("Program state not available, cannot continue execution"); } } + // Disabled due to unsafety. + /* "switch_backend" => { let backend_name = parts.next(); if backend_name.is_none() { @@ -731,6 +872,7 @@ fn interactive_shell(mut ctx: InteractiveShellContext) -> ShellExitOperation { println!("Program state not available, cannot continue execution"); } } + */ "backtrace" | "bt" => { if let Some(ref image) = ctx.image { println!("{}", image.execution_state.colored_output()); From b8c18215aa665825650fffad6caf10b7e353d313 Mon Sep 17 00:00:00 2001 From: losfair Date: Sat, 10 Aug 2019 02:32:14 +0800 Subject: [PATCH 16/90] Refactor tier switching code --- lib/llvm-backend/src/backend.rs | 4 +- lib/runtime-core/Cargo.toml | 1 + lib/runtime-core/src/fault.rs | 33 ++-- lib/runtime-core/src/lib.rs | 2 + lib/runtime-core/src/state.rs | 39 +++-- lib/runtime-core/src/tiering.rs | 236 +++++++++++++++++++++++++++ src/bin/wasmer.rs | 277 ++++---------------------------- 7 files changed, 318 insertions(+), 274 deletions(-) create mode 100644 lib/runtime-core/src/tiering.rs diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index f1d3f347a70..89cdfb4f265 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -287,11 +287,13 @@ impl LLVMBackend { ) }; + /* + static SIGNAL_HANDLER_INSTALLED: Once = Once::new(); SIGNAL_HANDLER_INSTALLED.call_once(|| unsafe { crate::platform::install_signal_handler(); - }); + });*/ if res != LLVMResult::OK { panic!("failed to load object") diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml index 4538cc44227..c504ed9dd10 100644 --- a/lib/runtime-core/Cargo.toml +++ b/lib/runtime-core/Cargo.toml @@ -57,3 +57,4 @@ trace = ["debug"] # backend flags used in conditional compilation of Backend::variants "backend-singlepass" = [] "backend-llvm" = [] +managed = [] \ No newline at end of file diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index 0fde80daf20..79795855657 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -9,6 +9,7 @@ mod raw { } use crate::codegen::{BreakpointInfo, BreakpointMap}; +use crate::state::CodeVersion; use crate::state::x64::{build_instance_image, read_stack, X64Register, GPR, XMM}; use crate::vm; use libc::{mmap, mprotect, siginfo_t, MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE}; @@ -17,7 +18,7 @@ use nix::sys::signal::{ SIGSEGV, SIGTRAP, }; use std::any::Any; -use std::cell::{Cell, UnsafeCell}; +use std::cell::{Cell, UnsafeCell, RefCell}; use std::ffi::c_void; use std::process; use std::sync::atomic::{AtomicBool, Ordering}; @@ -41,6 +42,7 @@ struct UnwindInfo { thread_local! { static UNWIND: UnsafeCell> = UnsafeCell::new(None); static CURRENT_CTX: UnsafeCell<*mut vm::Ctx> = UnsafeCell::new(::std::ptr::null_mut()); + static CURRENT_CODE_VERSIONS: RefCell> = RefCell::new(vec![]); static WAS_SIGINT_TRIGGERED: Cell = Cell::new(false); } @@ -83,6 +85,14 @@ pub unsafe fn with_ctx R>(ctx: *mut vm::Ctx, cb: F) -> R { ret } +pub fn push_code_version(version: CodeVersion) { + CURRENT_CODE_VERSIONS.with(|x| x.borrow_mut().push(version)); +} + +pub fn pop_code_version() -> Option { + CURRENT_CODE_VERSIONS.with(|x| x.borrow_mut().pop()) +} + pub unsafe fn get_wasm_interrupt_signal_mem() -> *mut u8 { INTERRUPT_SIGNAL_MEM.0 } @@ -242,18 +252,15 @@ 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 msm = (*ctx.module) - .runnable_module - .get_module_state_map() - .unwrap(); - let code_base = (*ctx.module).runnable_module.get_code().unwrap().as_ptr() as usize; - let es_image = read_stack( - &msm, - code_base, - rsp as usize as *const u64, - fault.known_registers, - Some(fault.ip as usize as u64), - ); + 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 as usize as u64), + ) + }); if is_suspend_signal { let image = build_instance_image(ctx, es_image); diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index a164f4727bf..b5e35dd7a53 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -47,6 +47,8 @@ pub use trampoline_x64 as trampoline; #[cfg(all(unix, target_arch = "x86_64"))] pub mod fault; pub mod state; +#[cfg(feature = "managed")] +pub mod tiering; use self::error::CompileResult; #[doc(inline)] diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index e33d2d11d22..d099768dd56 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -102,6 +102,12 @@ pub struct InstanceImage { pub execution_state: ExecutionStateImage, } +#[derive(Debug, Clone)] +pub struct CodeVersion { + pub msm: ModuleStateMap, + pub base: usize, +} + impl ModuleStateMap { fn lookup_ip &BTreeMap>( &self, @@ -739,9 +745,8 @@ pub mod x64 { } #[warn(unused_variables)] - pub unsafe fn read_stack( - msm: &ModuleStateMap, - code_base: usize, + pub unsafe fn read_stack<'a, I: Iterator, F: Fn() -> I + 'a>( + versions: F, mut stack: *const u64, initially_known_registers: [Option; 24], mut initial_address: Option, @@ -755,13 +760,27 @@ pub mod x64 { stack = stack.offset(1); x }); - let (fsm, state) = match msm - .lookup_call_ip(ret_addr as usize, code_base) - .or_else(|| msm.lookup_trappable_ip(ret_addr as usize, code_base)) - .or_else(|| msm.lookup_loop_ip(ret_addr as usize, code_base)) - { - Some(x) => x, - _ => return ExecutionStateImage { frames: results }, + + let mut fsm_state: Option<(&FunctionStateMap, MachineState)> = None; + + for version in versions() { + match version.msm + .lookup_call_ip(ret_addr as usize, version.base) + .or_else(|| version.msm.lookup_trappable_ip(ret_addr as usize, version.base)) + .or_else(|| version.msm.lookup_loop_ip(ret_addr as usize, version.base)) + { + Some(x) => { + fsm_state = Some(x); + break; + }, + None => {}, + }; + } + + let (fsm, state) = if let Some(x) = fsm_state { + x + } else { + return ExecutionStateImage { frames: results }; }; let mut wasm_stack: Vec> = state diff --git a/lib/runtime-core/src/tiering.rs b/lib/runtime-core/src/tiering.rs new file mode 100644 index 00000000000..54472e90c83 --- /dev/null +++ b/lib/runtime-core/src/tiering.rs @@ -0,0 +1,236 @@ +use crate::backend::{Compiler, CompilerConfig}; +use crate::import::ImportObject; +use crate::fault::{ + catch_unsafe_unwind, ensure_sighandler, with_ctx, push_code_version, pop_code_version, +}; +use crate::state::{ + x64::invoke_call_return_on_stack, InstanceImage, CodeVersion +}; +use crate::vm::Ctx; +use crate::compile_with_config; +use crate::instance::Instance; +use crate::fault::{set_wasm_interrupt_on_ctx, was_sigint_triggered_fault}; +use crate::module::{Module, ModuleInfo}; + +use std::sync::{Arc, Mutex}; +use std::cell::Cell; + +struct Defer(Option); +impl Drop for Defer { + fn drop(&mut self) { + if let Some(f) = self.0.take() { + f(); + } + } +} + +pub enum ShellExitOperation { + ContinueWith(InstanceImage), +} + +pub struct InteractiveShellContext { + pub image: Option, +} + +struct OptimizationState { + outcome: Mutex>, +} + +struct OptimizationOutcome { + module: Module, +} + +#[repr(transparent)] +struct CtxWrapper(*mut Ctx); +unsafe impl Send for CtxWrapper {} +unsafe impl Sync for CtxWrapper {} + +unsafe fn do_optimize( + binary: &[u8], + compiler: Box, + ctx: &Mutex, + state: &OptimizationState, +) { + let module = match compile_with_config( + &binary[..], + &*compiler, + CompilerConfig { + symbol_map: None, + track_state: true, + ..Default::default() + }, + ) { + Ok(x) => x, + Err(_) => return, + }; + + let ctx_inner = ctx.lock().unwrap(); + if !ctx_inner.0.is_null() { + *state.outcome.lock().unwrap() = Some(OptimizationOutcome { module }); + set_wasm_interrupt_on_ctx(ctx_inner.0); + } +} + +pub fn run_tiering ShellExitOperation>( + module_info: &ModuleInfo, + wasm_binary: &[u8], + mut resume_image: Option, + import_object: &ImportObject, + start_raw: extern "C" fn(&mut Ctx), + baseline: &mut Instance, + optimized_backends: Vec Box + Send>>, + interactive_shell: F, +) -> Result<(), String> { + unsafe { + ensure_sighandler(); + + let ctx_box = + Arc::new(Mutex::new(CtxWrapper(baseline.context_mut() as *mut _))); + // Ensure that the ctx pointer's lifetime is not longer than Instance's. + let _deferred_ctx_box_cleanup: Defer<_> = { + let ctx_box = ctx_box.clone(); + Defer(Some(move || { + ctx_box.lock().unwrap().0 = ::std::ptr::null_mut(); + })) + }; + let opt_state = Arc::new(OptimizationState { + outcome: Mutex::new(None), + }); + + { + let wasm_binary = wasm_binary.to_vec(); + let ctx_box = ctx_box.clone(); + let opt_state = opt_state.clone(); + ::std::thread::spawn(move || { + for backend in optimized_backends { + if !ctx_box.lock().unwrap().0.is_null() { + do_optimize( + &wasm_binary, + backend(), + &ctx_box, + &opt_state, + ); + } + } + }); + } + + let mut optimized_instances: Vec = vec![]; + + push_code_version(CodeVersion { + msm: baseline.module.runnable_module.get_module_state_map().unwrap(), + base: baseline.module.runnable_module.get_code().unwrap().as_ptr() as usize, + }); + let n_versions: Cell = Cell::new(1); + + let _deferred_pop_versions = Defer(Some(|| { + for _ in 0..n_versions.get() { + pop_code_version().unwrap(); + } + })); + + loop { + let new_optimized: Option<&mut Instance> = { + let mut outcome = opt_state.outcome.lock().unwrap(); + if let Some(x) = outcome.take() { + let instance = + x.module.instantiate(&import_object).map_err(|e| { + format!("Can't instantiate module: {:?}", e) + })?; + // Keep the optimized code alive. + optimized_instances.push(instance); + optimized_instances.last_mut() + } else { + None + } + }; + if let Some(optimized) = new_optimized { + let base = module_info.imported_functions.len(); + let code_ptr = optimized + .module + .runnable_module + .get_code() + .unwrap() + .as_ptr() + as usize; + let target_addresses: Vec = optimized + .module + .runnable_module + .get_local_function_offsets() + .unwrap() + .into_iter() + .map(|x| code_ptr + x) + .collect(); + assert_eq!( + target_addresses.len(), + module_info.func_assoc.len() - base + ); + for i in base..module_info.func_assoc.len() { + baseline + .module + .runnable_module + .patch_local_function(i - base, target_addresses[i - base]); + } + + push_code_version(CodeVersion { + msm: optimized.module.runnable_module.get_module_state_map().unwrap(), + base: optimized.module.runnable_module.get_code().unwrap().as_ptr() as usize, + }); + n_versions.set(n_versions.get() + 1); + + eprintln!("Patched"); + } + // TODO: Fix this for optimized version. + let breakpoints = baseline.module.runnable_module.get_breakpoints(); + let ctx = baseline.context_mut() as *mut _; + let ret = with_ctx(ctx, || { + if let Some(image) = resume_image.take() { + let msm = baseline + .module + .runnable_module + .get_module_state_map() + .unwrap(); + let code_base = + baseline.module.runnable_module.get_code().unwrap().as_ptr() + as usize; + invoke_call_return_on_stack( + &msm, + code_base, + image, + baseline.context_mut(), + breakpoints.clone(), + ) + .map(|_| ()) + } else { + catch_unsafe_unwind( + || start_raw(baseline.context_mut()), + breakpoints.clone(), + ) + } + }); + if let Err(e) = ret { + if let Some(new_image) = e.downcast_ref::() { + // Tier switch event + if !was_sigint_triggered_fault() + && opt_state.outcome.lock().unwrap().is_some() + { + resume_image = Some(new_image.clone()); + continue; + } + let op = interactive_shell(InteractiveShellContext { + image: Some(new_image.clone()), + }); + match op { + ShellExitOperation::ContinueWith(new_image) => { + resume_image = Some(new_image); + } + } + } else { + return Err("Error while executing WebAssembly".into()); + } + } else { + return Ok(()); + } + } + } +} diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index f9cb7c5f94b..b88aea2c8fc 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -9,7 +9,6 @@ use std::io::Read; use std::path::PathBuf; use std::process::exit; use std::str::FromStr; -use std::sync::{Arc, Mutex}; use hashbrown::HashMap; use structopt::StructOpt; @@ -26,14 +25,14 @@ use wasmer_runtime_core::{ self, backend::{Backend, Compiler, CompilerConfig, MemoryBoundCheckMode}, debug, - fault::{set_wasm_interrupt_on_ctx, was_sigint_triggered_fault}, loader::{Instance as LoadedInstance, LocalLoader}, - Instance, Module, }; #[cfg(feature = "backend-singlepass")] use wasmer_singlepass_backend::SinglePassCompiler; #[cfg(feature = "wasi")] use wasmer_wasi; +#[cfg(feature = "managed")] +use wasmer_runtime_core::tiering::{InteractiveShellContext, ShellExitOperation, run_tiering}; // stub module to make conditional compilation happy #[cfg(not(feature = "wasi"))] @@ -190,55 +189,6 @@ struct Validate { path: PathBuf, } -struct OptimizationState { - outcome: Mutex>, -} - -struct OptimizationOutcome { - module: Module, -} - -struct Defer(Option); -impl Drop for Defer { - fn drop(&mut self) { - if let Some(f) = self.0.take() { - f(); - } - } -} - -#[repr(transparent)] -struct CtxWrapper(*mut wasmer_runtime_core::vm::Ctx); -unsafe impl Send for CtxWrapper {} -unsafe impl Sync for CtxWrapper {} - -#[cfg(feature = "managed")] -unsafe fn begin_optimize( - binary: Vec, - compiler: Box, - ctx: Arc>, - state: Arc, -) { - let module = match webassembly::compile_with_config_with( - &binary[..], - CompilerConfig { - symbol_map: None, - track_state: true, - ..Default::default() - }, - &*compiler, - ) { - Ok(x) => x, - Err(_) => return, - }; - - let ctx_inner = ctx.lock().unwrap(); - if !ctx_inner.0.is_null() { - *state.outcome.lock().unwrap() = Some(OptimizationOutcome { module }); - set_wasm_interrupt_on_ctx(ctx_inner.0); - } -} - /// Read the contents of a file fn read_file_contents(path: &PathBuf) -> Result, io::Error> { let mut buffer: Vec = Vec::new(); @@ -556,194 +506,32 @@ fn execute_wasm(options: &Run) -> Result<(), String> { .map_err(|e| format!("Can't instantiate module: {:?}", e))?; let start: Func<(), ()> = instance.func("_start").map_err(|e| format!("{:?}", e))?; + let start_raw: extern "C" fn(&mut wasmer_runtime_core::vm::Ctx) = unsafe { + ::std::mem::transmute(start.get_vm_func()) + }; #[cfg(feature = "managed")] - unsafe { - if options.backend == Backend::Singlepass { - use wasmer_runtime_core::fault::{ - catch_unsafe_unwind, ensure_sighandler, with_ctx, - }; - use wasmer_runtime_core::state::{ - x64::invoke_call_return_on_stack, InstanceImage, - }; - use wasmer_runtime_core::vm::Ctx; - - ensure_sighandler(); - - let start_raw: extern "C" fn(&mut Ctx) = - ::std::mem::transmute(start.get_vm_func()); - - let mut image: Option = 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(InstanceImage::from_bytes(&out).expect("failed to decode image")) - } else { - None - }; - - let ctx_box = - Arc::new(Mutex::new(CtxWrapper(instance.context_mut() as *mut _))); - // Ensure that the ctx pointer's lifetime is not longer than Instance's. - let _deferred_ctx_box_cleanup: Defer<_> = { - let ctx_box = ctx_box.clone(); - Defer(Some(move || { - ctx_box.lock().unwrap().0 = ::std::ptr::null_mut(); - })) - }; - let opt_state = Arc::new(OptimizationState { - outcome: Mutex::new(None), - }); - - { - let wasm_binary = wasm_binary.to_vec(); - let ctx_box = ctx_box.clone(); - let opt_state = opt_state.clone(); - ::std::thread::spawn(move || { - // TODO: CLI option for optimized backend - begin_optimize( - wasm_binary, - get_compiler_by_backend(Backend::LLVM).unwrap(), - ctx_box, - opt_state, - ); - }); - } - - let mut patched = false; - let mut optimized_instance: Option = None; - - loop { - let optimized: Option<&mut Instance> = - if let Some(ref mut x) = optimized_instance { - Some(x) - } else { - let mut outcome = opt_state.outcome.lock().unwrap(); - if let Some(x) = outcome.take() { - let instance = - x.module.instantiate(&import_object).map_err(|e| { - format!("Can't instantiate module: {:?}", e) - })?; - optimized_instance = Some(instance); - optimized_instance.as_mut() - } else { - None - } - }; - if !patched && false { - if let Some(optimized) = optimized { - let base = module.info().imported_functions.len(); - let code_ptr = optimized - .module - .runnable_module - .get_code() - .unwrap() - .as_ptr() - as usize; - let target_addresses: Vec = optimized - .module - .runnable_module - .get_local_function_offsets() - .unwrap() - .into_iter() - .map(|x| code_ptr + x) - .collect(); - assert_eq!( - target_addresses.len(), - module.info().func_assoc.len() - base - ); - for i in base..module.info().func_assoc.len() { - instance - .module - .runnable_module - .patch_local_function(i - base, target_addresses[i - base]); - } - patched = true; - eprintln!("Patched"); - } - } - let breakpoints = instance.module.runnable_module.get_breakpoints(); - let ctx = instance.context_mut() as *mut _; - let ret = with_ctx(ctx, || { - if let Some(image) = image.take() { - let msm = instance - .module - .runnable_module - .get_module_state_map() - .unwrap(); - let code_base = - instance.module.runnable_module.get_code().unwrap().as_ptr() - as usize; - invoke_call_return_on_stack( - &msm, - code_base, - image, - instance.context_mut(), - breakpoints.clone(), - ) - .map(|_| ()) - } else { - catch_unsafe_unwind( - || start_raw(instance.context_mut()), - breakpoints.clone(), - ) - } - }); - if let Err(e) = ret { - if let Some(new_image) = e.downcast_ref::() { - // Tier switch event - if !was_sigint_triggered_fault() - && optimized_instance.is_none() - && opt_state.outcome.lock().unwrap().is_some() - { - image = Some(new_image.clone()); - continue; - } - let op = interactive_shell(InteractiveShellContext { - image: Some(new_image.clone()), - }); - match op { - ShellExitOperation::ContinueWith(new_image, new_backend) => { - image = Some(new_image); - if let Some(new_backend) = new_backend { - let compiler = - match get_compiler_by_backend(new_backend) { - Some(x) => x, - None => { - return Err( - "the requested backend is not enabled" - .into(), - ) - } - }; - let module = webassembly::compile_with_config_with( - &wasm_binary[..], - CompilerConfig { - symbol_map: em_symbol_map.clone(), - track_state, - ..Default::default() - }, - &*compiler, - ) - .map_err(|e| { - format!("Can't compile module: {:?}", e) - })?; - instance = module.instantiate(&import_object).map_err( - |e| format!("Can't instantiate module: {:?}", e), - )?; - } - } - } - } else { - return Err("Error while executing WebAssembly".into()); - } - } else { - return Ok(()); - } - } - } - } - + 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, + vec![ + Box::new(|| get_compiler_by_backend(Backend::LLVM).unwrap()), + ], + interactive_shell, + )?; + + #[cfg(not(feature = "managed"))] { use wasmer_runtime::error::RuntimeError; let result = start.call(); @@ -783,17 +571,6 @@ fn execute_wasm(options: &Run) -> Result<(), String> { Ok(()) } -#[cfg(feature = "managed")] -struct InteractiveShellContext { - image: Option, -} - -#[cfg(feature = "managed")] -#[derive(Debug)] -enum ShellExitOperation { - ContinueWith(wasmer_runtime_core::state::InstanceImage, Option), -} - #[cfg(feature = "managed")] fn interactive_shell(mut ctx: InteractiveShellContext) -> ShellExitOperation { use std::io::Write; @@ -844,7 +621,7 @@ fn interactive_shell(mut ctx: InteractiveShellContext) -> ShellExitOperation { } "continue" | "c" => { if let Some(image) = ctx.image.take() { - return ShellExitOperation::ContinueWith(image, None); + return ShellExitOperation::ContinueWith(image); } else { println!("Program state not available, cannot continue execution"); } From 8dfdd82865ea5567963004183fb2758b67a9593a Mon Sep 17 00:00:00 2001 From: losfair Date: Sat, 10 Aug 2019 02:32:33 +0800 Subject: [PATCH 17/90] Enable managed feature in wasmer-runtime-core --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 25d21c64d70..36bba73efff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,6 +76,7 @@ fast-tests = [] "backend-llvm" = ["wasmer-llvm-backend", "wasmer-runtime-core/backend-llvm"] "backend-singlepass" = ["wasmer-singlepass-backend", "wasmer-runtime-core/backend-singlepass"] wasi = ["wasmer-wasi"] +managed = ["backend-singlepass", "wasmer-runtime-core/managed"] # vfs = ["wasmer-runtime-abi"] [[example]] From 03665fe74a806e935b1d68813685af6a064f1710 Mon Sep 17 00:00:00 2001 From: losfair Date: Sat, 10 Aug 2019 02:43:21 +0800 Subject: [PATCH 18/90] Add CLI option for optimized backends. --- src/bin/wasmer.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index b88aea2c8fc..0d561ad63aa 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -119,6 +119,15 @@ struct Run { #[structopt(long = "resume")] resume: Option, + /// Optimized backends for higher tiers. + #[cfg(feature = "managed")] + #[structopt( + long = "optimized-backends", + multiple = true, + raw(possible_values = "Backend::variants()", case_insensitive = "true") + )] + optimized_backends: Vec, + /// Whether or not state tracking should be disabled during compilation. /// State tracking is necessary for tier switching and backtracing. #[structopt(long = "no-track-state")] @@ -525,9 +534,9 @@ fn execute_wasm(options: &Run) -> Result<(), String> { &import_object, start_raw, &mut instance, - vec![ - Box::new(|| get_compiler_by_backend(Backend::LLVM).unwrap()), - ], + options.optimized_backends.iter().map(|&backend| -> Box Box + Send> { + Box::new(move || get_compiler_by_backend(backend).unwrap()) + }).collect(), interactive_shell, )?; From 2e89f02191364fce434cc7e4f3b696f9edade782 Mon Sep 17 00:00:00 2001 From: losfair Date: Sat, 10 Aug 2019 02:44:44 +0800 Subject: [PATCH 19/90] Cargo fmt --- lib/runtime-core/src/fault.rs | 4 +- lib/runtime-core/src/state.rs | 13 ++++-- lib/runtime-core/src/tiering.rs | 72 ++++++++++++++++----------------- src/bin/wasmer.rs | 24 ++++++----- 4 files changed, 60 insertions(+), 53 deletions(-) diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index 79795855657..3cb6e7531a1 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -9,8 +9,8 @@ mod raw { } use crate::codegen::{BreakpointInfo, BreakpointMap}; -use crate::state::CodeVersion; use crate::state::x64::{build_instance_image, read_stack, X64Register, GPR, XMM}; +use crate::state::CodeVersion; use crate::vm; use libc::{mmap, mprotect, siginfo_t, MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE}; use nix::sys::signal::{ @@ -18,7 +18,7 @@ use nix::sys::signal::{ SIGSEGV, SIGTRAP, }; use std::any::Any; -use std::cell::{Cell, UnsafeCell, RefCell}; +use std::cell::{Cell, RefCell, UnsafeCell}; use std::ffi::c_void; use std::process; use std::sync::atomic::{AtomicBool, Ordering}; diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index d099768dd56..42785d29427 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -764,16 +764,21 @@ pub mod x64 { let mut fsm_state: Option<(&FunctionStateMap, MachineState)> = None; for version in versions() { - match version.msm + match version + .msm .lookup_call_ip(ret_addr as usize, version.base) - .or_else(|| version.msm.lookup_trappable_ip(ret_addr as usize, version.base)) + .or_else(|| { + version + .msm + .lookup_trappable_ip(ret_addr as usize, version.base) + }) .or_else(|| version.msm.lookup_loop_ip(ret_addr as usize, version.base)) { Some(x) => { fsm_state = Some(x); break; - }, - None => {}, + } + None => {} }; } diff --git a/lib/runtime-core/src/tiering.rs b/lib/runtime-core/src/tiering.rs index 54472e90c83..75688bab450 100644 --- a/lib/runtime-core/src/tiering.rs +++ b/lib/runtime-core/src/tiering.rs @@ -1,19 +1,17 @@ use crate::backend::{Compiler, CompilerConfig}; -use crate::import::ImportObject; +use crate::compile_with_config; use crate::fault::{ - catch_unsafe_unwind, ensure_sighandler, with_ctx, push_code_version, pop_code_version, -}; -use crate::state::{ - x64::invoke_call_return_on_stack, InstanceImage, CodeVersion + catch_unsafe_unwind, ensure_sighandler, pop_code_version, push_code_version, with_ctx, }; -use crate::vm::Ctx; -use crate::compile_with_config; -use crate::instance::Instance; use crate::fault::{set_wasm_interrupt_on_ctx, was_sigint_triggered_fault}; +use crate::import::ImportObject; +use crate::instance::Instance; use crate::module::{Module, ModuleInfo}; +use crate::state::{x64::invoke_call_return_on_stack, CodeVersion, InstanceImage}; +use crate::vm::Ctx; -use std::sync::{Arc, Mutex}; use std::cell::Cell; +use std::sync::{Arc, Mutex}; struct Defer(Option); impl Drop for Defer { @@ -84,8 +82,7 @@ pub fn run_tiering ShellExitOperation>( unsafe { ensure_sighandler(); - let ctx_box = - Arc::new(Mutex::new(CtxWrapper(baseline.context_mut() as *mut _))); + let ctx_box = Arc::new(Mutex::new(CtxWrapper(baseline.context_mut() as *mut _))); // Ensure that the ctx pointer's lifetime is not longer than Instance's. let _deferred_ctx_box_cleanup: Defer<_> = { let ctx_box = ctx_box.clone(); @@ -104,12 +101,7 @@ pub fn run_tiering ShellExitOperation>( ::std::thread::spawn(move || { for 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(), &ctx_box, &opt_state); } } }); @@ -118,7 +110,11 @@ pub fn run_tiering ShellExitOperation>( let mut optimized_instances: Vec = vec![]; push_code_version(CodeVersion { - msm: baseline.module.runnable_module.get_module_state_map().unwrap(), + msm: baseline + .module + .runnable_module + .get_module_state_map() + .unwrap(), base: baseline.module.runnable_module.get_code().unwrap().as_ptr() as usize, }); let n_versions: Cell = Cell::new(1); @@ -133,10 +129,10 @@ pub fn run_tiering ShellExitOperation>( let new_optimized: Option<&mut Instance> = { let mut outcome = opt_state.outcome.lock().unwrap(); if let Some(x) = outcome.take() { - let instance = - x.module.instantiate(&import_object).map_err(|e| { - format!("Can't instantiate module: {:?}", e) - })?; + let instance = x + .module + .instantiate(&import_object) + .map_err(|e| format!("Can't instantiate module: {:?}", e))?; // Keep the optimized code alive. optimized_instances.push(instance); optimized_instances.last_mut() @@ -151,8 +147,7 @@ pub fn run_tiering ShellExitOperation>( .runnable_module .get_code() .unwrap() - .as_ptr() - as usize; + .as_ptr() as usize; let target_addresses: Vec = optimized .module .runnable_module @@ -161,10 +156,7 @@ pub fn run_tiering ShellExitOperation>( .into_iter() .map(|x| code_ptr + x) .collect(); - assert_eq!( - target_addresses.len(), - module_info.func_assoc.len() - base - ); + assert_eq!(target_addresses.len(), module_info.func_assoc.len() - base); for i in base..module_info.func_assoc.len() { baseline .module @@ -173,8 +165,17 @@ pub fn run_tiering ShellExitOperation>( } push_code_version(CodeVersion { - msm: optimized.module.runnable_module.get_module_state_map().unwrap(), - base: optimized.module.runnable_module.get_code().unwrap().as_ptr() as usize, + msm: optimized + .module + .runnable_module + .get_module_state_map() + .unwrap(), + base: optimized + .module + .runnable_module + .get_code() + .unwrap() + .as_ptr() as usize, }); n_versions.set(n_versions.get() + 1); @@ -191,8 +192,7 @@ pub fn run_tiering ShellExitOperation>( .get_module_state_map() .unwrap(); let code_base = - baseline.module.runnable_module.get_code().unwrap().as_ptr() - as usize; + baseline.module.runnable_module.get_code().unwrap().as_ptr() as usize; invoke_call_return_on_stack( &msm, code_base, @@ -202,17 +202,13 @@ pub fn run_tiering ShellExitOperation>( ) .map(|_| ()) } else { - catch_unsafe_unwind( - || start_raw(baseline.context_mut()), - breakpoints.clone(), - ) + catch_unsafe_unwind(|| start_raw(baseline.context_mut()), breakpoints.clone()) } }); if let Err(e) = ret { if let Some(new_image) = e.downcast_ref::() { // Tier switch event - if !was_sigint_triggered_fault() - && opt_state.outcome.lock().unwrap().is_some() + if !was_sigint_triggered_fault() && opt_state.outcome.lock().unwrap().is_some() { resume_image = Some(new_image.clone()); continue; diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 0d561ad63aa..07bf68d5c22 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -21,6 +21,8 @@ use wasmer_runtime::{ cache::{Cache as BaseCache, FileSystemCache, WasmHash, WASMER_VERSION_HASH}, Func, Value, }; +#[cfg(feature = "managed")] +use wasmer_runtime_core::tiering::{run_tiering, InteractiveShellContext, ShellExitOperation}; use wasmer_runtime_core::{ self, backend::{Backend, Compiler, CompilerConfig, MemoryBoundCheckMode}, @@ -31,8 +33,6 @@ use wasmer_runtime_core::{ use wasmer_singlepass_backend::SinglePassCompiler; #[cfg(feature = "wasi")] use wasmer_wasi; -#[cfg(feature = "managed")] -use wasmer_runtime_core::tiering::{InteractiveShellContext, ShellExitOperation, run_tiering}; // stub module to make conditional compilation happy #[cfg(not(feature = "wasi"))] @@ -515,9 +515,8 @@ fn execute_wasm(options: &Run) -> Result<(), String> { .map_err(|e| format!("Can't instantiate module: {:?}", e))?; let start: Func<(), ()> = instance.func("_start").map_err(|e| format!("{:?}", e))?; - let start_raw: extern "C" fn(&mut wasmer_runtime_core::vm::Ctx) = unsafe { - ::std::mem::transmute(start.get_vm_func()) - }; + let start_raw: extern "C" fn(&mut wasmer_runtime_core::vm::Ctx) = + unsafe { ::std::mem::transmute(start.get_vm_func()) }; #[cfg(feature = "managed")] run_tiering( @@ -527,16 +526,23 @@ fn execute_wasm(options: &Run) -> Result<(), String> { 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")) + 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(), + options + .optimized_backends + .iter() + .map(|&backend| -> Box Box + Send> { + Box::new(move || get_compiler_by_backend(backend).unwrap()) + }) + .collect(), interactive_shell, )?; From d61a8bb6d2a95a4ec45f996e222e0c86cde56cf0 Mon Sep 17 00:00:00 2001 From: losfair Date: Sat, 10 Aug 2019 03:10:12 +0800 Subject: [PATCH 20/90] Prevent continueing execution on unreliable stack. (LLVM register save area information is missing) --- lib/runtime-core/src/tiering.rs | 4 ++-- src/bin/wasmer.rs | 36 +++++++++------------------------ 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/lib/runtime-core/src/tiering.rs b/lib/runtime-core/src/tiering.rs index 75688bab450..36ec19a1a8f 100644 --- a/lib/runtime-core/src/tiering.rs +++ b/lib/runtime-core/src/tiering.rs @@ -28,6 +28,7 @@ pub enum ShellExitOperation { pub struct InteractiveShellContext { pub image: Option, + pub patched: bool, } struct OptimizationState { @@ -178,8 +179,6 @@ pub fn run_tiering ShellExitOperation>( .as_ptr() as usize, }); n_versions.set(n_versions.get() + 1); - - eprintln!("Patched"); } // TODO: Fix this for optimized version. let breakpoints = baseline.module.runnable_module.get_breakpoints(); @@ -215,6 +214,7 @@ pub fn run_tiering ShellExitOperation>( } let op = interactive_shell(InteractiveShellContext { image: Some(new_image.clone()), + patched: n_versions.get() > 1, }); match op { ShellExitOperation::ContinueWith(new_image) => { diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 07bf68d5c22..a68ef2190ec 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -635,37 +635,21 @@ fn interactive_shell(mut ctx: InteractiveShellContext) -> ShellExitOperation { } } "continue" | "c" => { - if let Some(image) = ctx.image.take() { - return ShellExitOperation::ContinueWith(image); + if ctx.patched { + println!("Error: Continueing execution is not yet supported on patched code."); } else { - println!("Program state not available, cannot continue execution"); - } - } - // Disabled due to unsafety. - /* - "switch_backend" => { - let backend_name = parts.next(); - if backend_name.is_none() { - println!("Usage: switch_backend [backend_name]"); - continue; - } - let backend_name = backend_name.unwrap(); - let backend = match backend_name { - "singlepass" => Backend::Singlepass, - "llvm" => Backend::LLVM, - _ => { - println!("unknown backend"); - continue; + if let Some(image) = ctx.image.take() { + return ShellExitOperation::ContinueWith(image); + } else { + println!("Program state not available, cannot continue execution"); } - }; - if let Some(image) = ctx.image.take() { - return ShellExitOperation::ContinueWith(image, Some(backend)); - } else { - println!("Program state not available, cannot continue execution"); } } - */ "backtrace" | "bt" => { + if ctx.patched { + println!("Warning: Backtrace on patched code might be inaccurate."); + } + if let Some(ref image) = ctx.image { println!("{}", image.execution_state.colored_output()); } else { From 9cade2b44179a46ee197cf4ed73fe069b81e5ad6 Mon Sep 17 00:00:00 2001 From: losfair Date: Sat, 10 Aug 2019 03:10:32 +0800 Subject: [PATCH 21/90] singlepass: Skip patchpoint. --- lib/singlepass-backend/src/codegen_x64.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 081b067a913..aad03402d53 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -1679,6 +1679,7 @@ impl FunctionCodeGenerator for X64FunctionCode { fn begin_body(&mut self, _module_info: &ModuleInfo) -> Result<(), CodegenError> { let a = self.assembler.as_mut().unwrap(); let start_label = a.get_label(); + a.emit_jmp(Condition::None, start_label); // patchpoint of 16 bytes for _ in 0..16 { a.emit_nop(); From 44f71759f64866fc8e29683116695fddece3b084 Mon Sep 17 00:00:00 2001 From: losfair Date: Sat, 10 Aug 2019 03:23:29 +0800 Subject: [PATCH 22/90] Use Vec::with_capacity in various places. --- lib/llvm-backend/src/backend.rs | 4 +++- lib/llvm-backend/src/code.rs | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index 89cdfb4f265..8e532067fa3 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -321,7 +321,9 @@ impl LLVMBackend { total_size: code_size, }; - let mut local_func_id_to_addr: Vec = Vec::new(); + let num_local_functions = + module_info.func_assoc.len() - module_info.imported_functions.len(); + let mut local_func_id_to_addr: Vec = Vec::with_capacity(num_local_functions); // All local functions. for index in module_info.imported_functions.len()..module_info.func_assoc.len() { diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index dea3d101204..27da39244c5 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -316,7 +316,7 @@ fn emit_stack_map( ) { let stackmap_id = target.entries.len(); - let mut params = vec![]; + let mut params = Vec::with_capacity(2 + locals.len() + state.stack.len()); params.push( intrinsics @@ -327,7 +327,8 @@ fn emit_stack_map( params.push(intrinsics.i32_ty.const_int(0, false).as_basic_value_enum()); let locals: Vec<_> = locals.iter().map(|x| x.as_basic_value_enum()).collect(); - let mut value_semantics: Vec = vec![]; + let mut value_semantics: Vec = + Vec::with_capacity(locals.len() + state.stack.len()); params.extend_from_slice(&locals); value_semantics.extend((0..locals.len()).map(ValueSemantic::WasmLocal)); From 98ef9182d79a0e267ba21448199f667f5c0a0fdf Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 14 Aug 2019 16:35:40 -0700 Subject: [PATCH 23/90] Run clang-format and cargo fmt --- lib/llvm-backend/cpp/object_loader.cpp | 208 +++++++++++----------- lib/llvm-backend/cpp/object_loader.hh | 58 +++--- lib/singlepass-backend/src/codegen_x64.rs | 4 +- src/bin/wasmer.rs | 2 +- 4 files changed, 134 insertions(+), 138 deletions(-) diff --git a/lib/llvm-backend/cpp/object_loader.cpp b/lib/llvm-backend/cpp/object_loader.cpp index ee443a075c6..18a48847bb3 100644 --- a/lib/llvm-backend/cpp/object_loader.cpp +++ b/lib/llvm-backend/cpp/object_loader.cpp @@ -7,91 +7,92 @@ extern "C" void __deregister_frame(uint8_t *); struct MemoryManager : llvm::RuntimeDyld::MemoryManager { public: - MemoryManager(callbacks_t callbacks) : callbacks(callbacks) {} + MemoryManager(callbacks_t callbacks) : callbacks(callbacks) {} - uint8_t * get_stack_map_ptr() const { - return stack_map_ptr; - } + uint8_t *get_stack_map_ptr() const { return stack_map_ptr; } - size_t get_stack_map_size() const { - return stack_map_size; - } + size_t get_stack_map_size() const { return stack_map_size; } - uint8_t * get_code_ptr() const { - return (uint8_t *) code_start_ptr; - } + uint8_t *get_code_ptr() const { return (uint8_t *)code_start_ptr; } - size_t get_code_size() const { - return code_size; - } + size_t get_code_size() const { return code_size; } - virtual ~MemoryManager() override { - deregisterEHFrames(); - // Deallocate all of the allocated memory. - callbacks.dealloc_memory(code_section.base, code_section.size); - callbacks.dealloc_memory(read_section.base, read_section.size); - callbacks.dealloc_memory(readwrite_section.base, readwrite_section.size); - } + virtual ~MemoryManager() override { + deregisterEHFrames(); + // Deallocate all of the allocated memory. + callbacks.dealloc_memory(code_section.base, code_section.size); + callbacks.dealloc_memory(read_section.base, read_section.size); + callbacks.dealloc_memory(readwrite_section.base, readwrite_section.size); + } - virtual uint8_t* allocateCodeSection(uintptr_t size, unsigned alignment, unsigned section_id, llvm::StringRef section_name) override { - return allocate_bump(code_section, code_bump_ptr, size, alignment); - } + virtual uint8_t *allocateCodeSection(uintptr_t size, unsigned alignment, + unsigned section_id, + llvm::StringRef section_name) override { + return allocate_bump(code_section, code_bump_ptr, size, alignment); + } - virtual uint8_t* allocateDataSection(uintptr_t size, unsigned alignment, unsigned section_id, llvm::StringRef section_name, bool read_only) override { - // Allocate from the read-only section or the read-write section, depending on if this allocation - // should be read-only or not. - uint8_t *ret; - if (read_only) { - ret = allocate_bump(read_section, read_bump_ptr, size, alignment); - } else { - ret = allocate_bump(readwrite_section, readwrite_bump_ptr, size, alignment); - } - if(section_name.equals(llvm::StringRef("__llvm_stackmaps")) || section_name.equals(llvm::StringRef(".llvm_stackmaps"))) { - stack_map_ptr = ret; - stack_map_size = size; - } - return ret; + virtual uint8_t *allocateDataSection(uintptr_t size, unsigned alignment, + unsigned section_id, + llvm::StringRef section_name, + bool read_only) override { + // Allocate from the read-only section or the read-write section, depending + // on if this allocation should be read-only or not. + uint8_t *ret; + if (read_only) { + ret = allocate_bump(read_section, read_bump_ptr, size, alignment); + } else { + ret = + allocate_bump(readwrite_section, readwrite_bump_ptr, size, alignment); } - - virtual void reserveAllocationSpace( - uintptr_t code_size, - uint32_t code_align, - uintptr_t read_data_size, - uint32_t read_data_align, - uintptr_t read_write_data_size, - uint32_t read_write_data_align - ) override { - auto aligner = [](uintptr_t ptr, size_t align) { - if (ptr == 0) { - return align; - } - return (ptr + align - 1) & ~(align - 1); - }; - - - uint8_t *code_ptr_out = nullptr; - size_t code_size_out = 0; - auto code_result = callbacks.alloc_memory(aligner(code_size, 4096), PROTECT_READ_WRITE, &code_ptr_out, &code_size_out); - assert(code_result == RESULT_OK); - code_section = Section { code_ptr_out, code_size_out }; - code_bump_ptr = (uintptr_t)code_ptr_out; - code_start_ptr = (uintptr_t)code_ptr_out; - this->code_size = code_size; - - uint8_t *read_ptr_out = nullptr; - size_t read_size_out = 0; - auto read_result = callbacks.alloc_memory(aligner(read_data_size, 4096), PROTECT_READ_WRITE, &read_ptr_out, &read_size_out); - assert(read_result == RESULT_OK); - read_section = Section { read_ptr_out, read_size_out }; - read_bump_ptr = (uintptr_t)read_ptr_out; - - uint8_t *readwrite_ptr_out = nullptr; - size_t readwrite_size_out = 0; - auto readwrite_result = callbacks.alloc_memory(aligner(read_write_data_size, 4096), PROTECT_READ_WRITE, &readwrite_ptr_out, &readwrite_size_out); - assert(readwrite_result == RESULT_OK); - readwrite_section = Section { readwrite_ptr_out, readwrite_size_out }; - readwrite_bump_ptr = (uintptr_t)readwrite_ptr_out; + if (section_name.equals(llvm::StringRef("__llvm_stackmaps")) || + section_name.equals(llvm::StringRef(".llvm_stackmaps"))) { + stack_map_ptr = ret; + stack_map_size = size; } + return ret; + } + + virtual void reserveAllocationSpace(uintptr_t code_size, uint32_t code_align, + uintptr_t read_data_size, + uint32_t read_data_align, + uintptr_t read_write_data_size, + uint32_t read_write_data_align) override { + auto aligner = [](uintptr_t ptr, size_t align) { + if (ptr == 0) { + return align; + } + return (ptr + align - 1) & ~(align - 1); + }; + + uint8_t *code_ptr_out = nullptr; + size_t code_size_out = 0; + auto code_result = + callbacks.alloc_memory(aligner(code_size, 4096), PROTECT_READ_WRITE, + &code_ptr_out, &code_size_out); + assert(code_result == RESULT_OK); + code_section = Section{code_ptr_out, code_size_out}; + code_bump_ptr = (uintptr_t)code_ptr_out; + code_start_ptr = (uintptr_t)code_ptr_out; + this->code_size = code_size; + + uint8_t *read_ptr_out = nullptr; + size_t read_size_out = 0; + auto read_result = callbacks.alloc_memory(aligner(read_data_size, 4096), + PROTECT_READ_WRITE, &read_ptr_out, + &read_size_out); + assert(read_result == RESULT_OK); + read_section = Section{read_ptr_out, read_size_out}; + read_bump_ptr = (uintptr_t)read_ptr_out; + + uint8_t *readwrite_ptr_out = nullptr; + size_t readwrite_size_out = 0; + auto readwrite_result = callbacks.alloc_memory( + aligner(read_write_data_size, 4096), PROTECT_READ_WRITE, + &readwrite_ptr_out, &readwrite_size_out); + assert(readwrite_result == RESULT_OK); + readwrite_section = Section{readwrite_ptr_out, readwrite_size_out}; + readwrite_bump_ptr = (uintptr_t)readwrite_ptr_out; + } /* Turn on the `reserveAllocationSpace` callback. */ virtual bool needsToReserveAllocationSpace() override { return true; } @@ -164,18 +165,18 @@ struct MemoryManager : llvm::RuntimeDyld::MemoryManager { return (uint8_t *)ret_ptr; } - Section code_section, read_section, readwrite_section; - uintptr_t code_start_ptr; - size_t code_size; - uintptr_t code_bump_ptr, read_bump_ptr, readwrite_bump_ptr; - uint8_t* eh_frame_ptr; - size_t eh_frame_size; - bool eh_frames_registered = false; + Section code_section, read_section, readwrite_section; + uintptr_t code_start_ptr; + size_t code_size; + uintptr_t code_bump_ptr, read_bump_ptr, readwrite_bump_ptr; + uint8_t *eh_frame_ptr; + size_t eh_frame_size; + bool eh_frames_registered = false; - callbacks_t callbacks; + callbacks_t callbacks; - uint8_t *stack_map_ptr = nullptr; - size_t stack_map_size = 0; + uint8_t *stack_map_ptr = nullptr; + size_t stack_map_size = 0; }; struct SymbolLookup : llvm::JITSymbolResolver { @@ -235,32 +236,31 @@ WasmModule::WasmModule(const uint8_t *object_start, size_t object_size, } } -void* WasmModule::get_func(llvm::StringRef name) const { - auto symbol = runtime_dyld->getSymbol(name); - return (void*)symbol.getAddress(); +void *WasmModule::get_func(llvm::StringRef name) const { + auto symbol = runtime_dyld->getSymbol(name); + return (void *)symbol.getAddress(); } -uint8_t * WasmModule::get_stack_map_ptr() const { - llvm::RuntimeDyld::MemoryManager& mm = *memory_manager; - MemoryManager *local_mm = dynamic_cast(&mm); - return local_mm->get_stack_map_ptr(); +uint8_t *WasmModule::get_stack_map_ptr() const { + llvm::RuntimeDyld::MemoryManager &mm = *memory_manager; + MemoryManager *local_mm = dynamic_cast(&mm); + return local_mm->get_stack_map_ptr(); } size_t WasmModule::get_stack_map_size() const { - llvm::RuntimeDyld::MemoryManager& mm = *memory_manager; - MemoryManager *local_mm = dynamic_cast(&mm); - return local_mm->get_stack_map_size(); + llvm::RuntimeDyld::MemoryManager &mm = *memory_manager; + MemoryManager *local_mm = dynamic_cast(&mm); + return local_mm->get_stack_map_size(); } - -uint8_t * WasmModule::get_code_ptr() const { - llvm::RuntimeDyld::MemoryManager& mm = *memory_manager; - MemoryManager *local_mm = dynamic_cast(&mm); - return local_mm->get_code_ptr(); +uint8_t *WasmModule::get_code_ptr() const { + llvm::RuntimeDyld::MemoryManager &mm = *memory_manager; + MemoryManager *local_mm = dynamic_cast(&mm); + return local_mm->get_code_ptr(); } size_t WasmModule::get_code_size() const { - llvm::RuntimeDyld::MemoryManager& mm = *memory_manager; - MemoryManager *local_mm = dynamic_cast(&mm); - return local_mm->get_code_size(); + llvm::RuntimeDyld::MemoryManager &mm = *memory_manager; + MemoryManager *local_mm = dynamic_cast(&mm); + return local_mm->get_code_size(); } diff --git a/lib/llvm-backend/cpp/object_loader.hh b/lib/llvm-backend/cpp/object_loader.hh index fd4dc3b7078..eb18ec600ac 100644 --- a/lib/llvm-backend/cpp/object_loader.hh +++ b/lib/llvm-backend/cpp/object_loader.hh @@ -83,25 +83,23 @@ public: uintptr_t callback; }; -struct WasmModule -{ - public: - WasmModule( - const uint8_t *object_start, - size_t object_size, - callbacks_t callbacks); - - void *get_func(llvm::StringRef name) const; - uint8_t *get_stack_map_ptr() const; - size_t get_stack_map_size() const; - uint8_t *get_code_ptr() const; - size_t get_code_size() const; - - bool _init_failed = false; - private: - std::unique_ptr memory_manager; - std::unique_ptr object_file; - std::unique_ptr runtime_dyld; +struct WasmModule { +public: + WasmModule(const uint8_t *object_start, size_t object_size, + callbacks_t callbacks); + + void *get_func(llvm::StringRef name) const; + uint8_t *get_stack_map_ptr() const; + size_t get_stack_map_size() const; + uint8_t *get_code_ptr() const; + size_t get_code_size() const; + + bool _init_failed = false; + +private: + std::unique_ptr memory_manager; + std::unique_ptr object_file; + std::unique_ptr runtime_dyld; }; struct WasmTrap : UncatchableException { @@ -225,18 +223,18 @@ void *get_func_symbol(WasmModule *module, const char *name) { } const uint8_t *llvm_backend_get_stack_map_ptr(const WasmModule *module) { - return module->get_stack_map_ptr(); - } + return module->get_stack_map_ptr(); +} - size_t llvm_backend_get_stack_map_size(const WasmModule *module) { - return module->get_stack_map_size(); - } +size_t llvm_backend_get_stack_map_size(const WasmModule *module) { + return module->get_stack_map_size(); +} - const uint8_t *llvm_backend_get_code_ptr(const WasmModule *module) { - return module->get_code_ptr(); - } +const uint8_t *llvm_backend_get_code_ptr(const WasmModule *module) { + return module->get_code_ptr(); +} - size_t llvm_backend_get_code_size(const WasmModule *module) { - return module->get_code_size(); - } +size_t llvm_backend_get_code_size(const WasmModule *module) { + return module->get_code_size(); +} } diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 7f2c6d91912..f805f071084 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -4,9 +4,7 @@ use crate::emitter_x64::*; use crate::machine::*; use crate::protect_unix; -use dynasmrt::{ - x64::Assembler, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi, -}; +use dynasmrt::{x64::Assembler, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi}; use smallvec::SmallVec; use std::ptr::NonNull; use std::{ diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index a509ce213f4..28d47f0edb3 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -579,7 +579,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { .map_err(|e| format!("Can't instantiate 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) = From c9e3db3d94db9a26a175e19b5acdd70b68dec1d7 Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 14 Aug 2019 16:41:44 -0700 Subject: [PATCH 24/90] Remove feature(core_intrinsics) --- lib/runtime-core/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index 34e4de8bcc9..139dda50a89 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -6,7 +6,6 @@ unreachable_patterns )] #![cfg_attr(nightly, feature(unwind_attributes))] -#![feature(core_intrinsics)] #[cfg(test)] #[macro_use] From 9edd9ffdfe3a27676a35a2b951d45539cda36cf5 Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 14 Aug 2019 17:14:01 -0700 Subject: [PATCH 25/90] Make lookup_*_ip public. --- lib/runtime-core/src/state.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 947fb77d0b8..9add4abaa32 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -109,7 +109,7 @@ pub struct CodeVersion { } impl ModuleStateMap { - fn lookup_ip &BTreeMap>( + pub fn lookup_ip &BTreeMap>( &self, ip: usize, base: usize, @@ -141,12 +141,12 @@ impl ModuleStateMap { } } } - fn lookup_call_ip(&self, ip: usize, base: usize) -> Option<(&FunctionStateMap, MachineState)> { + pub fn lookup_call_ip(&self, ip: usize, base: usize) -> Option<(&FunctionStateMap, MachineState)> { self.lookup_ip(ip, base, |fsm| &fsm.call_offsets) } #[warn(dead_code)] - fn lookup_trappable_ip( + pub fn lookup_trappable_ip( &self, ip: usize, base: usize, @@ -155,7 +155,7 @@ impl ModuleStateMap { } #[warn(dead_code)] - fn lookup_loop_ip(&self, ip: usize, base: usize) -> Option<(&FunctionStateMap, MachineState)> { + pub fn lookup_loop_ip(&self, ip: usize, base: usize) -> Option<(&FunctionStateMap, MachineState)> { self.lookup_ip(ip, base, |fsm| &fsm.loop_offsets) } } From 1582224d61e6e8be6731ced1eaade47c68e188e4 Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 14 Aug 2019 17:16:30 -0700 Subject: [PATCH 26/90] Cargo fmt --- lib/runtime-core/src/state.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 9add4abaa32..5526eaf3a87 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -141,7 +141,11 @@ impl ModuleStateMap { } } } - pub fn lookup_call_ip(&self, ip: usize, base: usize) -> Option<(&FunctionStateMap, MachineState)> { + pub fn lookup_call_ip( + &self, + ip: usize, + base: usize, + ) -> Option<(&FunctionStateMap, MachineState)> { self.lookup_ip(ip, base, |fsm| &fsm.call_offsets) } @@ -155,7 +159,11 @@ impl ModuleStateMap { } #[warn(dead_code)] - pub fn lookup_loop_ip(&self, ip: usize, base: usize) -> Option<(&FunctionStateMap, MachineState)> { + pub fn lookup_loop_ip( + &self, + ip: usize, + base: usize, + ) -> Option<(&FunctionStateMap, MachineState)> { self.lookup_ip(ip, base, |fsm| &fsm.loop_offsets) } } From 9471f643fd071f569607f42cddb26c0af0730a33 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 15 Aug 2019 19:03:39 -0700 Subject: [PATCH 27/90] Update iterative_hash example. --- examples/iterative_hash/src/main.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/examples/iterative_hash/src/main.rs b/examples/iterative_hash/src/main.rs index f25672047f4..fe92479ad9e 100644 --- a/examples/iterative_hash/src/main.rs +++ b/examples/iterative_hash/src/main.rs @@ -1,7 +1,12 @@ use blake2::{Blake2b, Digest}; +use std::time::{Duration, SystemTime}; fn main() { let mut data: Vec = b"test".to_vec(); + let now = SystemTime::now(); + + let mut last_millis: u128 = 0; + let mut round_count: usize = 0; for i in 0.. { let mut hasher = Blake2b::new(); @@ -9,8 +14,11 @@ fn main() { let out = hasher.result(); data = out.to_vec(); - if i % 1000000 == 0 { - println!("Round {}: {:?}", i, data); + if i % 100000 == 0 { + let millis = now.elapsed().unwrap().as_millis(); + println!("{} rounds in last second", (i - round_count) as f64 / (millis - last_millis) as f64); + last_millis = millis; + round_count = i; } } } From 7028df23efdec10018dcbc2d2a7ad9cb2cddafa4 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 15 Aug 2019 19:07:03 -0700 Subject: [PATCH 28/90] Allow only integers for LLVM function param/return values. --- lib/llvm-backend/src/backend.rs | 2 + lib/llvm-backend/src/code.rs | 82 +++++++++++++++++++++++------ lib/llvm-backend/src/stackmap.rs | 1 - lib/llvm-backend/src/trampolines.rs | 6 +-- 4 files changed, 69 insertions(+), 22 deletions(-) diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index e4dfd7de318..51284ccb8cb 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -218,6 +218,8 @@ impl LLVMBackend { ) }; + // Uncomment this to make spectests pass. + // TODO: fix this /* static SIGNAL_HANDLER_INSTALLED: Once = Once::new(); diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 8d44eb344e1..daca4282e60 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -34,7 +34,7 @@ use crate::stackmap::{StackmapEntry, StackmapEntryKind, StackmapRegistry, ValueS use crate::state::{ControlFrame, IfElseState, State}; use crate::trampolines::generate_trampolines; -fn func_sig_to_llvm(context: &Context, intrinsics: &Intrinsics, sig: &FuncSig) -> FunctionType { +fn func_sig_to_llvm(context: &Context, intrinsics: &Intrinsics, sig: &FuncSig, type_to_llvm: fn(intrinsics: &Intrinsics, ty: Type) -> BasicTypeEnum) -> FunctionType { 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,6 +67,14 @@ fn type_to_llvm(intrinsics: &Intrinsics, ty: Type) -> BasicTypeEnum { } } +fn type_to_llvm_int_only(intrinsics: &Intrinsics, ty: Type) -> BasicTypeEnum { + match ty { + Type::I32 | Type::F32 => intrinsics.i32_ty.as_basic_type_enum(), + Type::I64 | Type::F64 => intrinsics.i64_ty.as_basic_type_enum(), + Type::V128 => intrinsics.i128_ty.as_basic_type_enum(), + } +} + // Create a vector where each lane contains the same value. fn splat_vector( builder: &Builder, @@ -1210,6 +1218,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { // If llvm cannot prove that this is never touched, // it will emit a `ud2` instruction on x86_64 arches. + // Comment out this `if` block to allow spectests to pass. + // TODO: fix this if let Some(offset) = opcode_offset { let mut stackmaps = self.stackmaps.borrow_mut(); emit_stack_map( @@ -1425,10 +1435,15 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let (params, func_ptr) = match func_index.local_or_import(info) { LocalOrImport::Local(local_func_index) => { - let params: Vec<_> = [ctx.basic()] - .iter() - .chain(state.peekn(func_sig.params().len())?.iter()) - .map(|v| *v) + let params: Vec<_> = std::iter::once(ctx.basic()) + .chain( + state.peekn(func_sig.params().len())?.iter().enumerate() + .map(|(i, &v)| match func_sig.params()[i] { + Type::F32 => builder.build_bitcast(v, intrinsics.i32_ty, &state.var_name()), + Type::F64 => builder.build_bitcast(v, intrinsics.i64_ty, &state.var_name()), + _ => v + }) + ) .collect(); let func_ptr = @@ -1439,10 +1454,16 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { LocalOrImport::Import(import_func_index) => { let (func_ptr_untyped, ctx_ptr) = ctx.imported_func(import_func_index, intrinsics); - let params: Vec<_> = [ctx_ptr.as_basic_value_enum()] - .iter() - .chain(state.peekn(func_sig.params().len())?.iter()) - .map(|v| *v) + + let params: Vec<_> = std::iter::once(ctx_ptr.as_basic_value_enum()) + .chain( + state.peekn(func_sig.params().len())?.iter().enumerate() + .map(|(i, &v)| match func_sig.params()[i] { + Type::F32 => builder.build_bitcast(v, intrinsics.i32_ty, &state.var_name()), + Type::F64 => builder.build_bitcast(v, intrinsics.i64_ty, &state.var_name()), + _ => v + }) + ) .collect(); let func_ptr_ty = llvm_sig.ptr_type(AddressSpace::Generic); @@ -1488,7 +1509,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { if let Some(basic_value) = call_site.try_as_basic_value().left() { match func_sig.returns().len() { - 1 => state.push1(basic_value), + 1 => state.push1(match func_sig.returns()[0] { + Type::F32 => builder.build_bitcast(basic_value, intrinsics.f32_ty, "ret_cast"), + Type::F64 => builder.build_bitcast(basic_value, intrinsics.f64_ty, "ret_cast"), + _ => basic_value, + }), count @ _ => { // This is a multi-value return. let struct_value = basic_value.into_struct_value(); @@ -1640,8 +1665,15 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let pushed_args = state.popn_save(wasmer_fn_sig.params().len())?; let args: Vec<_> = std::iter::once(ctx_ptr) - .chain(pushed_args.into_iter()) - .collect(); + .chain( + pushed_args.into_iter().enumerate() + .map(|(i, v)| match wasmer_fn_sig.params()[i] { + Type::F32 => builder.build_bitcast(v, intrinsics.i32_ty, &state.var_name()), + Type::F64 => builder.build_bitcast(v, intrinsics.i64_ty, &state.var_name()), + _ => v + }) + ) + .collect(); let typed_func_ptr = builder.build_pointer_cast( func_ptr, @@ -1681,7 +1713,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { [] => {} [_] => { let value = call_site.try_as_basic_value().left().unwrap(); - state.push1(value); + state.push1(match wasmer_fn_sig.returns()[0] { + Type::F32 => builder.build_bitcast(value, intrinsics.f32_ty, "ret_cast"), + Type::F64 => builder.build_bitcast(value, intrinsics.f64_ty, "ret_cast"), + _ => value, + }); } _ => unimplemented!("multi-value returns"), } @@ -4779,7 +4815,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { self.builder.as_ref().unwrap().build_return(None); } [one_value] => { - self.builder.as_ref().unwrap().build_return(Some(one_value)); + let builder = self.builder.as_ref().unwrap(); + let intrinsics = self.intrinsics.as_ref().unwrap(); + builder.build_return(Some( + &builder.build_bitcast(one_value.as_basic_value_enum(), type_to_llvm_int_only(intrinsics, self.func_sig.returns()[0]), "return") + )); } _ => unimplemented!("multi-value returns not yet implemented"), } @@ -4888,10 +4928,17 @@ impl ModuleCodeGenerator .skip(1) .enumerate() .map(|(index, param)| { - let ty = param.get_type(); + //let ty = param.get_type(); + let real_ty = func_sig.params()[index]; + let real_ty_llvm = type_to_llvm(&intrinsics, real_ty); + + let alloca = builder.build_alloca(real_ty_llvm, &format!("local{}", index)); - let alloca = builder.build_alloca(ty, &format!("local{}", index)); - builder.build_store(alloca, param); + //if real_ty_llvm != ty { + builder.build_store(alloca, builder.build_bitcast(param, real_ty_llvm, &state.var_name())); + /*} else { + builder.build_store(alloca, param); + }*/ alloca }), ); @@ -4994,6 +5041,7 @@ impl ModuleCodeGenerator self.context.as_ref().unwrap(), self.intrinsics.as_ref().unwrap(), sig, + type_to_llvm_int_only, ) }) .collect(); diff --git a/lib/llvm-backend/src/stackmap.rs b/lib/llvm-backend/src/stackmap.rs index 4a27522835f..80cba160aab 100644 --- a/lib/llvm-backend/src/stackmap.rs +++ b/lib/llvm-backend/src/stackmap.rs @@ -228,7 +228,6 @@ impl StackmapEntry { ); if loc.offset_or_small_constant >= 0 { // FIXME: parameters passed on stack? - //eprintln!("XXX: {}", loc.offset_or_small_constant); } else { let stack_offset = ((-loc.offset_or_small_constant) / 4) as usize; assert!( diff --git a/lib/llvm-backend/src/trampolines.rs b/lib/llvm-backend/src/trampolines.rs index 95fd676b952..cebfa9d4671 100644 --- a/lib/llvm-backend/src/trampolines.rs +++ b/lib/llvm-backend/src/trampolines.rs @@ -68,10 +68,8 @@ fn generate_trampoline( }; let cast_ptr_ty = |wasmer_ty| match wasmer_ty { - Type::I32 => intrinsics.i32_ptr_ty, - Type::I64 => intrinsics.i64_ptr_ty, - Type::F32 => intrinsics.f32_ptr_ty, - Type::F64 => intrinsics.f64_ptr_ty, + Type::I32 | Type::F32 => intrinsics.i32_ptr_ty, + Type::I64 | Type::F64 => intrinsics.i64_ptr_ty, Type::V128 => intrinsics.i128_ptr_ty, }; From 0a54213d4fd358f8f5013c2911432dc0d6664da4 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 15 Aug 2019 19:08:11 -0700 Subject: [PATCH 29/90] register_preservation_trampoline --- lib/runtime-core/image-loading-linux-x86-64.s | 34 +++++++++++++++++++ lib/runtime-core/image-loading-macos-x86-64.s | 34 +++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/lib/runtime-core/image-loading-linux-x86-64.s b/lib/runtime-core/image-loading-linux-x86-64.s index 37ed0f98683..1d86bab0806 100644 --- a/lib/runtime-core/image-loading-linux-x86-64.s +++ b/lib/runtime-core/image-loading-linux-x86-64.s @@ -67,3 +67,37 @@ popq %r13 popq %r14 popq %r15 retq + +# For switching into a backend without information about where registers are preserved. +.globl register_preservation_trampoline +register_preservation_trampoline: +subq $8, %rsp +pushq %rax +pushq %rcx +pushq %rdx +pushq %rdi +pushq %rsi +pushq %r8 +pushq %r9 +pushq %r10 + +callq get_boundary_register_preservation + +# Keep this consistent with BoundaryRegisterPreservation +movq %r15, 0(%rax) +movq %r14, 8(%rax) +movq %r13, 16(%rax) +movq %r12, 24(%rax) +movq %rbx, 32(%rax) + +popq %r10 +popq %r9 +popq %r8 +popq %rsi +popq %rdi +popq %rdx +popq %rcx +popq %rax +addq $8, %rsp + +jmpq *%rax diff --git a/lib/runtime-core/image-loading-macos-x86-64.s b/lib/runtime-core/image-loading-macos-x86-64.s index a6a307f1fd4..ef6f9451060 100644 --- a/lib/runtime-core/image-loading-macos-x86-64.s +++ b/lib/runtime-core/image-loading-macos-x86-64.s @@ -67,3 +67,37 @@ popq %r13 popq %r14 popq %r15 retq + +# For switching into a backend without information about where registers are preserved. +.globl _register_preservation_trampoline +_register_preservation_trampoline: +subq $8, %rsp +pushq %rax +pushq %rcx +pushq %rdx +pushq %rdi +pushq %rsi +pushq %r8 +pushq %r9 +pushq %r10 + +callq _get_boundary_register_preservation + +# Keep this consistent with BoundaryRegisterPreservation +movq %r15, 0(%rax) +movq %r14, 8(%rax) +movq %r13, 16(%rax) +movq %r12, 24(%rax) +movq %rbx, 32(%rax) + +popq %r10 +popq %r9 +popq %r8 +popq %rsi +popq %rdi +popq %rdx +popq %rcx +popq %rax +addq $8, %rsp + +jmpq *%rax From 6a244859991ded2a2b9d2ea01437734e205c86b9 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 15 Aug 2019 19:10:24 -0700 Subject: [PATCH 30/90] Insert trampolines to preserve callee-saved registers for backends without register save area information. --- lib/runtime-core/src/fault.rs | 19 +++++++++++- lib/runtime-core/src/state.rs | 24 +++++++++++++-- lib/runtime-core/src/tiering.rs | 4 +++ lib/singlepass-backend/src/codegen_x64.rs | 36 +++++++++++++++-------- 4 files changed, 68 insertions(+), 15 deletions(-) diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index 7e41e00dbd9..2d46d8ca25c 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -1,8 +1,9 @@ -mod raw { +pub mod raw { use std::ffi::c_void; 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 pub fn setjmp(env: *mut c_void) -> i32; pub fn longjmp(env: *mut c_void, val: i32) -> !; } @@ -39,11 +40,27 @@ struct UnwindInfo { payload: Option>, // out } +#[repr(packed)] +#[derive(Default, Copy, Clone)] +pub struct BoundaryRegisterPreservation { + pub r15: u64, + pub r14: u64, + pub r13: u64, + pub r12: u64, + pub rbx: u64, +} + thread_local! { static UNWIND: UnsafeCell> = UnsafeCell::new(None); static CURRENT_CTX: UnsafeCell<*mut vm::Ctx> = UnsafeCell::new(::std::ptr::null_mut()); static CURRENT_CODE_VERSIONS: RefCell> = RefCell::new(vec![]); static WAS_SIGINT_TRIGGERED: Cell = Cell::new(false); + static BOUNDARY_REGISTER_PRESERVATION: UnsafeCell = UnsafeCell::new(BoundaryRegisterPreservation::default()); +} + +#[no_mangle] +pub unsafe extern "C" fn get_boundary_register_preservation() -> *mut BoundaryRegisterPreservation { + BOUNDARY_REGISTER_PRESERVATION.with(|x| x.get()) } struct InterruptSignalMem(*mut u8); diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 5526eaf3a87..93c353b8a92 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -104,6 +104,7 @@ pub struct InstanceImage { #[derive(Debug, Clone)] pub struct CodeVersion { + pub baseline: bool, pub msm: ModuleStateMap, pub base: usize, } @@ -372,7 +373,7 @@ impl InstanceImage { pub mod x64 { use super::*; use crate::codegen::BreakpointMap; - use crate::fault::{catch_unsafe_unwind, run_on_alternative_stack}; + use crate::fault::{catch_unsafe_unwind, run_on_alternative_stack, get_boundary_register_preservation}; use crate::structures::TypedIndex; use crate::types::LocalGlobalIndex; use crate::vm::Ctx; @@ -763,8 +764,9 @@ pub mod x64 { ) -> ExecutionStateImage { let mut known_registers: [Option; 24] = initially_known_registers; let mut results: Vec = vec![]; + let mut was_baseline = true; - for _ in 0.. { + for i in 0.. { let ret_addr = initial_address.take().unwrap_or_else(|| { let x = *stack; stack = stack.offset(1); @@ -772,6 +774,7 @@ pub mod x64 { }); let mut fsm_state: Option<(&FunctionStateMap, MachineState)> = None; + let mut is_baseline: Option = None; for version in versions() { match version @@ -786,6 +789,7 @@ pub mod x64 { { Some(x) => { fsm_state = Some(x); + is_baseline = Some(version.baseline); break; } None => {} @@ -798,6 +802,22 @@ pub mod x64 { return ExecutionStateImage { frames: results }; }; + { + let is_baseline = is_baseline.unwrap(); + + // Are we unwinding through an optimized/baseline boundary? + if is_baseline && !was_baseline { + let callee_saved = &*get_boundary_register_preservation(); + known_registers[X64Register::GPR(GPR::R15).to_index().0] = Some(callee_saved.r15); + known_registers[X64Register::GPR(GPR::R14).to_index().0] = Some(callee_saved.r14); + known_registers[X64Register::GPR(GPR::R13).to_index().0] = Some(callee_saved.r13); + known_registers[X64Register::GPR(GPR::R12).to_index().0] = Some(callee_saved.r12); + known_registers[X64Register::GPR(GPR::RBX).to_index().0] = Some(callee_saved.rbx); + } + + was_baseline = is_baseline; + } + let mut wasm_stack: Vec> = state .wasm_stack .iter() diff --git a/lib/runtime-core/src/tiering.rs b/lib/runtime-core/src/tiering.rs index 1025578efbe..b30da612849 100644 --- a/lib/runtime-core/src/tiering.rs +++ b/lib/runtime-core/src/tiering.rs @@ -111,6 +111,7 @@ pub fn run_tiering ShellExitOperation>( let mut optimized_instances: Vec = vec![]; push_code_version(CodeVersion { + baseline: true, msm: baseline .module .runnable_module @@ -166,6 +167,7 @@ pub fn run_tiering ShellExitOperation>( } push_code_version(CodeVersion { + baseline: false, msm: optimized .module .runnable_module @@ -179,6 +181,8 @@ pub fn run_tiering ShellExitOperation>( .as_ptr() as usize, }); n_versions.set(n_versions.get() + 1); + + baseline.context_mut().local_functions = optimized.context_mut().local_functions; } // TODO: Fix this for optimized version. let breakpoints = baseline.module.runnable_module.get_breakpoints(); diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index f805f071084..02ed8287b09 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -32,6 +32,7 @@ use wasmer_runtime_core::{ TableIndex, Type, }, vm::{self, LocalGlobal, LocalTable, INTERNALS_SIZE}, + fault::raw::register_preservation_trampoline, }; use wasmparser::{Operator, Type as WpType, TypeOrFuncType as WpTypeOrFuncType}; @@ -220,24 +221,34 @@ impl RunnableModule for X64ExecutionContext { } unsafe fn patch_local_function(&self, idx: usize, target_address: usize) -> bool { - // movabsq ?, %rax; - // jmpq *%rax; + + /* + 0: 48 b8 42 42 42 42 42 42 42 42 movabsq $4774451407313060418, %rax + a: 49 bb 43 43 43 43 43 43 43 43 movabsq $4846791580151137091, %r11 + 14: 41 ff e3 jmpq *%r11 + */ #[repr(packed)] struct Trampoline { - movabsq: [u8; 2], - addr: u64, - jmpq: [u8; 2], + movabsq_rax: [u8; 2], + addr_rax: u64, + movabsq_r11: [u8; 2], + addr_r11: u64, + jmpq_r11: [u8; 3], } self.code.make_writable(); let trampoline = &mut *(self.function_pointers[self.func_import_count + idx].0 as *const Trampoline as *mut Trampoline); - trampoline.movabsq[0] = 0x48; - trampoline.movabsq[1] = 0xb8; - trampoline.addr = target_address as u64; - trampoline.jmpq[0] = 0xff; - trampoline.jmpq[1] = 0xe0; + trampoline.movabsq_rax[0] = 0x48; + trampoline.movabsq_rax[1] = 0xb8; + trampoline.addr_rax = target_address as u64; + trampoline.movabsq_r11[0] = 0x49; + trampoline.movabsq_r11[1] = 0xbb; + trampoline.addr_r11 = register_preservation_trampoline as unsafe extern "C" fn() as usize as u64; + trampoline.jmpq_r11[0] = 0x41; + trampoline.jmpq_r11[1] = 0xff; + trampoline.jmpq_r11[2] = 0xe3; self.code.make_executable(); true @@ -1677,9 +1688,10 @@ impl FunctionCodeGenerator for X64FunctionCode { fn begin_body(&mut self, _module_info: &ModuleInfo) -> Result<(), CodegenError> { let a = self.assembler.as_mut().unwrap(); let start_label = a.get_label(); + // skip the patchpoint during normal execution a.emit_jmp(Condition::None, start_label); - // patchpoint of 16 bytes - for _ in 0..16 { + // patchpoint of 32 bytes + for _ in 0..32 { a.emit_nop(); } a.emit_label(start_label); From 8a1f399df69bcdc6c7f51e1a53d51d9f40f8cac3 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 15 Aug 2019 19:12:32 -0700 Subject: [PATCH 31/90] Fix NaN during first round issue in the iterative hash example. --- examples/iterative_hash/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/iterative_hash/src/main.rs b/examples/iterative_hash/src/main.rs index fe92479ad9e..d2937e4fbf9 100644 --- a/examples/iterative_hash/src/main.rs +++ b/examples/iterative_hash/src/main.rs @@ -14,7 +14,7 @@ fn main() { let out = hasher.result(); data = out.to_vec(); - if i % 100000 == 0 { + if i != 0 && i % 100000 == 0 { let millis = now.elapsed().unwrap().as_millis(); println!("{} rounds in last second", (i - round_count) as f64 / (millis - last_millis) as f64); last_millis = millis; From afa0600701106d9998a10fd1c35ee43ee4d29931 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 15 Aug 2019 19:13:00 -0700 Subject: [PATCH 32/90] Cargo fmt --- lib/llvm-backend/src/code.rs | 99 ++++++++++++++++------- lib/runtime-core/src/state.rs | 19 +++-- lib/singlepass-backend/src/codegen_x64.rs | 6 +- 3 files changed, 87 insertions(+), 37 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index daca4282e60..e349ad73902 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -34,7 +34,12 @@ use crate::stackmap::{StackmapEntry, StackmapEntryKind, StackmapRegistry, ValueS use crate::state::{ControlFrame, IfElseState, State}; use crate::trampolines::generate_trampolines; -fn func_sig_to_llvm(context: &Context, intrinsics: &Intrinsics, sig: &FuncSig, type_to_llvm: fn(intrinsics: &Intrinsics, ty: Type) -> BasicTypeEnum) -> FunctionType { +fn func_sig_to_llvm( + context: &Context, + intrinsics: &Intrinsics, + sig: &FuncSig, + type_to_llvm: fn(intrinsics: &Intrinsics, ty: Type) -> BasicTypeEnum, +) -> FunctionType { 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()) @@ -1437,12 +1442,23 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { LocalOrImport::Local(local_func_index) => { let params: Vec<_> = std::iter::once(ctx.basic()) .chain( - state.peekn(func_sig.params().len())?.iter().enumerate() + state + .peekn(func_sig.params().len())? + .iter() + .enumerate() .map(|(i, &v)| match func_sig.params()[i] { - Type::F32 => builder.build_bitcast(v, intrinsics.i32_ty, &state.var_name()), - Type::F64 => builder.build_bitcast(v, intrinsics.i64_ty, &state.var_name()), - _ => v - }) + Type::F32 => builder.build_bitcast( + v, + intrinsics.i32_ty, + &state.var_name(), + ), + Type::F64 => builder.build_bitcast( + v, + intrinsics.i64_ty, + &state.var_name(), + ), + _ => v, + }), ) .collect(); @@ -1457,12 +1473,23 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let params: Vec<_> = std::iter::once(ctx_ptr.as_basic_value_enum()) .chain( - state.peekn(func_sig.params().len())?.iter().enumerate() + state + .peekn(func_sig.params().len())? + .iter() + .enumerate() .map(|(i, &v)| match func_sig.params()[i] { - Type::F32 => builder.build_bitcast(v, intrinsics.i32_ty, &state.var_name()), - Type::F64 => builder.build_bitcast(v, intrinsics.i64_ty, &state.var_name()), - _ => v - }) + Type::F32 => builder.build_bitcast( + v, + intrinsics.i32_ty, + &state.var_name(), + ), + Type::F64 => builder.build_bitcast( + v, + intrinsics.i64_ty, + &state.var_name(), + ), + _ => v, + }), ) .collect(); @@ -1510,8 +1537,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { if let Some(basic_value) = call_site.try_as_basic_value().left() { match func_sig.returns().len() { 1 => state.push1(match func_sig.returns()[0] { - Type::F32 => builder.build_bitcast(basic_value, intrinsics.f32_ty, "ret_cast"), - Type::F64 => builder.build_bitcast(basic_value, intrinsics.f64_ty, "ret_cast"), + Type::F32 => { + builder.build_bitcast(basic_value, intrinsics.f32_ty, "ret_cast") + } + Type::F64 => { + builder.build_bitcast(basic_value, intrinsics.f64_ty, "ret_cast") + } _ => basic_value, }), count @ _ => { @@ -1665,15 +1696,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let pushed_args = state.popn_save(wasmer_fn_sig.params().len())?; let args: Vec<_> = std::iter::once(ctx_ptr) - .chain( - pushed_args.into_iter().enumerate() - .map(|(i, v)| match wasmer_fn_sig.params()[i] { - Type::F32 => builder.build_bitcast(v, intrinsics.i32_ty, &state.var_name()), - Type::F64 => builder.build_bitcast(v, intrinsics.i64_ty, &state.var_name()), - _ => v - }) - ) - .collect(); + .chain(pushed_args.into_iter().enumerate().map(|(i, v)| { + match wasmer_fn_sig.params()[i] { + Type::F32 => { + builder.build_bitcast(v, intrinsics.i32_ty, &state.var_name()) + } + Type::F64 => { + builder.build_bitcast(v, intrinsics.i64_ty, &state.var_name()) + } + _ => v, + } + })) + .collect(); let typed_func_ptr = builder.build_pointer_cast( func_ptr, @@ -1714,8 +1748,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { [_] => { let value = call_site.try_as_basic_value().left().unwrap(); state.push1(match wasmer_fn_sig.returns()[0] { - Type::F32 => builder.build_bitcast(value, intrinsics.f32_ty, "ret_cast"), - Type::F64 => builder.build_bitcast(value, intrinsics.f64_ty, "ret_cast"), + Type::F32 => { + builder.build_bitcast(value, intrinsics.f32_ty, "ret_cast") + } + Type::F64 => { + builder.build_bitcast(value, intrinsics.f64_ty, "ret_cast") + } _ => value, }); } @@ -4817,9 +4855,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { [one_value] => { let builder = self.builder.as_ref().unwrap(); let intrinsics = self.intrinsics.as_ref().unwrap(); - builder.build_return(Some( - &builder.build_bitcast(one_value.as_basic_value_enum(), type_to_llvm_int_only(intrinsics, self.func_sig.returns()[0]), "return") - )); + builder.build_return(Some(&builder.build_bitcast( + one_value.as_basic_value_enum(), + type_to_llvm_int_only(intrinsics, self.func_sig.returns()[0]), + "return", + ))); } _ => unimplemented!("multi-value returns not yet implemented"), } @@ -4935,7 +4975,10 @@ impl ModuleCodeGenerator let alloca = builder.build_alloca(real_ty_llvm, &format!("local{}", index)); //if real_ty_llvm != ty { - builder.build_store(alloca, builder.build_bitcast(param, real_ty_llvm, &state.var_name())); + builder.build_store( + alloca, + builder.build_bitcast(param, real_ty_llvm, &state.var_name()), + ); /*} else { builder.build_store(alloca, param); }*/ diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 93c353b8a92..ed5f1fff77c 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -373,7 +373,9 @@ impl InstanceImage { pub mod x64 { use super::*; use crate::codegen::BreakpointMap; - use crate::fault::{catch_unsafe_unwind, run_on_alternative_stack, get_boundary_register_preservation}; + use crate::fault::{ + catch_unsafe_unwind, get_boundary_register_preservation, run_on_alternative_stack, + }; use crate::structures::TypedIndex; use crate::types::LocalGlobalIndex; use crate::vm::Ctx; @@ -808,11 +810,16 @@ pub mod x64 { // Are we unwinding through an optimized/baseline boundary? if is_baseline && !was_baseline { let callee_saved = &*get_boundary_register_preservation(); - known_registers[X64Register::GPR(GPR::R15).to_index().0] = Some(callee_saved.r15); - known_registers[X64Register::GPR(GPR::R14).to_index().0] = Some(callee_saved.r14); - known_registers[X64Register::GPR(GPR::R13).to_index().0] = Some(callee_saved.r13); - known_registers[X64Register::GPR(GPR::R12).to_index().0] = Some(callee_saved.r12); - known_registers[X64Register::GPR(GPR::RBX).to_index().0] = Some(callee_saved.rbx); + known_registers[X64Register::GPR(GPR::R15).to_index().0] = + Some(callee_saved.r15); + known_registers[X64Register::GPR(GPR::R14).to_index().0] = + Some(callee_saved.r14); + known_registers[X64Register::GPR(GPR::R13).to_index().0] = + Some(callee_saved.r13); + known_registers[X64Register::GPR(GPR::R12).to_index().0] = + Some(callee_saved.r12); + known_registers[X64Register::GPR(GPR::RBX).to_index().0] = + Some(callee_saved.rbx); } was_baseline = is_baseline; diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 02ed8287b09..caca3075760 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -18,6 +18,7 @@ use wasmer_runtime_core::{ }, cache::{Artifact, Error as CacheError}, codegen::*, + fault::raw::register_preservation_trampoline, loader::CodeMemory, memory::MemoryType, module::{ModuleInfo, ModuleInner}, @@ -32,7 +33,6 @@ use wasmer_runtime_core::{ TableIndex, Type, }, vm::{self, LocalGlobal, LocalTable, INTERNALS_SIZE}, - fault::raw::register_preservation_trampoline, }; use wasmparser::{Operator, Type as WpType, TypeOrFuncType as WpTypeOrFuncType}; @@ -221,7 +221,6 @@ impl RunnableModule for X64ExecutionContext { } unsafe fn patch_local_function(&self, idx: usize, target_address: usize) -> bool { - /* 0: 48 b8 42 42 42 42 42 42 42 42 movabsq $4774451407313060418, %rax a: 49 bb 43 43 43 43 43 43 43 43 movabsq $4846791580151137091, %r11 @@ -245,7 +244,8 @@ impl RunnableModule for X64ExecutionContext { trampoline.addr_rax = target_address as u64; trampoline.movabsq_r11[0] = 0x49; trampoline.movabsq_r11[1] = 0xbb; - trampoline.addr_r11 = register_preservation_trampoline as unsafe extern "C" fn() as usize as u64; + trampoline.addr_r11 = + register_preservation_trampoline as unsafe extern "C" fn() as usize as u64; trampoline.jmpq_r11[0] = 0x41; trampoline.jmpq_r11[1] = 0xff; trampoline.jmpq_r11[2] = 0xe3; From be4ea764a0a40ba368ce4212f8c8fe3498db955f Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 15 Aug 2019 19:37:54 -0700 Subject: [PATCH 33/90] Update iterative_hash example for benchmarking --- examples/iterative_hash/src/main.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/examples/iterative_hash/src/main.rs b/examples/iterative_hash/src/main.rs index d2937e4fbf9..043bc02a1d4 100644 --- a/examples/iterative_hash/src/main.rs +++ b/examples/iterative_hash/src/main.rs @@ -7,6 +7,7 @@ fn main() { let mut last_millis: u128 = 0; let mut round_count: usize = 0; + let mut record_count: usize = 0; for i in 0.. { let mut hasher = Blake2b::new(); @@ -14,11 +15,15 @@ fn main() { let out = hasher.result(); data = out.to_vec(); - if i != 0 && i % 100000 == 0 { + if i != 0 && i % 1000 == 0 { let millis = now.elapsed().unwrap().as_millis(); - println!("{} rounds in last second", (i - round_count) as f64 / (millis - last_millis) as f64); - last_millis = millis; - round_count = i; + let diff = millis - last_millis; + if diff >= 100 { + record_count += 1; + println!("{}", (i - round_count) as f64 / diff as f64); + last_millis = millis; + round_count = i; + } } } } From dbaa000e96fe298d19c61bbcde645aa9bda07c45 Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 16 Aug 2019 13:08:10 -0700 Subject: [PATCH 34/90] Re-enable snapshotting. --- lib/runtime-core/src/state.rs | 2 +- lib/runtime-core/src/tiering.rs | 8 ++++---- src/bin/wasmer.rs | 14 +++----------- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index ed5f1fff77c..c2d25c76350 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -768,7 +768,7 @@ pub mod x64 { let mut results: Vec = vec![]; let mut was_baseline = true; - for i in 0.. { + for _ in 0.. { let ret_addr = initial_address.take().unwrap_or_else(|| { let x = *stack; stack = stack.offset(1); diff --git a/lib/runtime-core/src/tiering.rs b/lib/runtime-core/src/tiering.rs index b30da612849..4c5b8505509 100644 --- a/lib/runtime-core/src/tiering.rs +++ b/lib/runtime-core/src/tiering.rs @@ -184,7 +184,7 @@ pub fn run_tiering ShellExitOperation>( baseline.context_mut().local_functions = optimized.context_mut().local_functions; } - // TODO: Fix this for optimized version. + // Assuming we do not want to do breakpoint-based debugging on optimized backends. let breakpoints = baseline.module.runnable_module.get_breakpoints(); let ctx = baseline.context_mut() as *mut _; let ret = with_ctx(ctx, || { @@ -209,15 +209,15 @@ pub fn run_tiering ShellExitOperation>( } }); if let Err(e) = ret { - if let Some(new_image) = e.downcast_ref::() { + if let Ok(new_image) = e.downcast::() { // Tier switch event if !was_sigint_triggered_fault() && opt_state.outcome.lock().unwrap().is_some() { - resume_image = Some(new_image.clone()); + resume_image = Some(*new_image); continue; } let op = interactive_shell(InteractiveShellContext { - image: Some(new_image.clone()), + image: Some(*new_image), patched: n_versions.get() > 1, }); match op { diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 28d47f0edb3..e12c0db941a 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -705,21 +705,13 @@ fn interactive_shell(mut ctx: InteractiveShellContext) -> ShellExitOperation { } } "continue" | "c" => { - if ctx.patched { - println!("Error: Continueing execution is not yet supported on patched code."); + if let Some(image) = ctx.image.take() { + return ShellExitOperation::ContinueWith(image); } else { - if let Some(image) = ctx.image.take() { - return ShellExitOperation::ContinueWith(image); - } else { - println!("Program state not available, cannot continue execution"); - } + println!("Program state not available, cannot continue execution"); } } "backtrace" | "bt" => { - if ctx.patched { - println!("Warning: Backtrace on patched code might be inaccurate."); - } - if let Some(ref image) = ctx.image { println!("{}", image.execution_state.colored_output()); } else { From 4e6267aa57609760157c2f7aaa6b710fdb9cced3 Mon Sep 17 00:00:00 2001 From: losfair Date: Mon, 19 Aug 2019 19:12:33 -0700 Subject: [PATCH 35/90] Correctly handle more than 5 WASM function parameters when reading state of a LLVM context. --- lib/llvm-backend/src/stackmap.rs | 9 ++++-- lib/runtime-core/src/state.rs | 47 ++++++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/lib/llvm-backend/src/stackmap.rs b/lib/llvm-backend/src/stackmap.rs index 80cba160aab..7e4d515df2a 100644 --- a/lib/llvm-backend/src/stackmap.rs +++ b/lib/llvm-backend/src/stackmap.rs @@ -1,7 +1,7 @@ // https://llvm.org/docs/StackMaps.html#stackmap-section use byteorder::{LittleEndian, ReadBytesExt}; -use std::collections::HashMap; +use std::collections::{HashMap, BTreeMap}; use std::io::{self, Cursor}; use wasmer_runtime_core::state::{ x64::{new_machine_state, X64Register, GPR}, @@ -128,6 +128,8 @@ impl StackmapEntry { let mut regs: Vec<(RegisterIndex, MachineValue)> = vec![]; let mut stack_constants: HashMap = HashMap::new(); + let mut prev_frame_diff: BTreeMap> = BTreeMap::new(); + let mut wasm_locals: Vec = vec![]; let mut wasm_stack: Vec = vec![]; @@ -227,7 +229,9 @@ impl StackmapEntry { == X64Register::GPR(GPR::RBP) ); if loc.offset_or_small_constant >= 0 { - // FIXME: parameters passed on stack? + assert!(loc.offset_or_small_constant >= 16); // (saved_rbp, return_address) + assert!(loc.offset_or_small_constant % 8 == 0); + prev_frame_diff.insert(((loc.offset_or_small_constant as usize - 16) / 8), Some(mv)); } else { let stack_offset = ((-loc.offset_or_small_constant) / 4) as usize; assert!( @@ -280,6 +284,7 @@ impl StackmapEntry { last: None, stack_push: machine_stack_layout, stack_pop: 0, + prev_frame_diff, reg_diff: regs, wasm_stack_push: wasm_stack, wasm_stack_pop: 0, diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index c2d25c76350..580318842ff 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -15,6 +15,8 @@ pub struct MachineState { pub stack_values: Vec, pub register_values: Vec, + pub prev_frame: BTreeMap, + pub wasm_stack: Vec, pub wasm_stack_private_depth: usize, @@ -28,6 +30,8 @@ pub struct MachineStateDiff { pub stack_pop: usize, pub reg_diff: Vec<(RegisterIndex, MachineValue)>, + pub prev_frame_diff: BTreeMap>, // None for removal + pub wasm_stack_push: Vec, pub wasm_stack_pop: usize, pub wasm_stack_private_depth: usize, // absolute value; not a diff. @@ -210,6 +214,22 @@ impl MachineState { .filter(|&(_, (a, b))| a != b) .map(|(i, (a, _))| (RegisterIndex(i), a.clone())) .collect(); + let prev_frame_diff: BTreeMap> = self + .prev_frame + .iter() + .filter(|(k, v)| if let Some(ref old_v) = old.prev_frame.get(k) { + v != old_v + } else { + true + }) + .map(|(&k, v)| (k, Some(v.clone()))) + .chain( + old.prev_frame + .iter() + .filter(|(k, _)| self.prev_frame.get(k).is_none()) + .map(|(&k, _)| (k, None)) + ) + .collect(); let first_diff_wasm_stack_depth: usize = self .wasm_stack .iter() @@ -222,7 +242,9 @@ impl MachineState { last: None, stack_push: self.stack_values[first_diff_stack_depth..].to_vec(), stack_pop: old.stack_values.len() - first_diff_stack_depth, - reg_diff: reg_diff, + reg_diff, + + prev_frame_diff, wasm_stack_push: self.wasm_stack[first_diff_wasm_stack_depth..].to_vec(), wasm_stack_pop: old.wasm_stack.len() - first_diff_wasm_stack_depth, @@ -255,6 +277,13 @@ impl MachineStateDiff { for &(index, ref v) in &x.reg_diff { state.register_values[index.0] = v.clone(); } + for (index, ref v) in &x.prev_frame_diff { + if let Some(ref x) = v { + state.prev_frame.insert(*index, x.clone()); + } else { + state.prev_frame.remove(index).unwrap(); + } + } for _ in 0..x.wasm_stack_pop { state.wasm_stack.pop().unwrap(); } @@ -393,6 +422,7 @@ pub mod x64 { MachineState { stack_values: vec![], register_values: vec![MachineValue::Undefined; 16 + 8], + prev_frame: BTreeMap::new(), wasm_stack: vec![], wasm_stack_private_depth: 0, wasm_inst_offset: ::std::usize::MAX, @@ -938,7 +968,20 @@ pub mod x64 { } } } - stack = stack.offset(1); // RBP + + for (offset, v) in state.prev_frame.iter() { + let offset = (*offset + 2) as isize; // (saved_rbp, return_address) + match *v { + MachineValue::WasmStack(idx) => { + wasm_stack[idx] = Some(*stack.offset(offset)); + } + MachineValue::WasmLocal(idx) => { + wasm_locals[idx] = Some(*stack.offset(offset)); + } + _ => unreachable!("values in prev frame can only be stack/local") + } + } + stack = stack.offset(1); // saved_rbp wasm_stack.truncate( wasm_stack From 942298facdb914dca449f9542c3ee4f187c9146c Mon Sep 17 00:00:00 2001 From: losfair Date: Mon, 19 Aug 2019 19:13:27 -0700 Subject: [PATCH 36/90] Add test case for params passed on stack. --- examples/many_params.wat | 56 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 examples/many_params.wat diff --git a/examples/many_params.wat b/examples/many_params.wat new file mode 100644 index 00000000000..3794871989a --- /dev/null +++ b/examples/many_params.wat @@ -0,0 +1,56 @@ +;; Test case for correctness of reading state with the presence of parameters passed on (machine) stack. +;; Usage: Run with a backend with support for OSR. Interrupt execution randomly. +;; Should see the stack frame for `$foo` to have locals `[0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 5, [5] = 6, [6] = 7, [7] = 8` with high probability. + +(module + (import "wasi_unstable" "proc_exit" (func $__wasi_proc_exit (param i32))) + (func $long_running + (local $count i32) + (loop + (if (i32.eq (get_local $count) (i32.const 1000000)) (then (return))) + (set_local $count (i32.add (i32.const 1) (get_local $count))) + (br 0) + ) + (unreachable) + ) + + (func $foo (param i32) (param i64) (param i32) (param i32) (param i32) (param i64) (param i64) (param i64) (result i32) + (set_local 2 (i32.const 3)) + (call $long_running) + (i32.add + (i32.mul (i32.const 2) (get_local 0)) + (i32.add + (i32.mul (i32.const 3) (i32.wrap/i64 (get_local 1))) + (i32.add + (i32.mul (i32.const 5) (get_local 2)) + (i32.add + (i32.mul (i32.const 7) (get_local 3)) + (i32.add + (i32.mul (i32.const 11) (get_local 4)) + (i32.add + (i32.mul (i32.const 13) (i32.wrap/i64 (get_local 5))) + (i32.add + (i32.mul (i32.const 17) (i32.wrap/i64 (get_local 6))) + (i32.mul (i32.const 19) (i32.wrap/i64 (get_local 7))) + ) + ) + ) + ) + ) + ) + ) + ) + (func $_start (export "_start") + (local $count i32) + (loop + (if (i32.eq (get_local $count) (i32.const 10000)) (then (return))) + (set_local $count (i32.add (i32.const 1) (get_local $count))) + (call $foo (i32.const 1) (i64.const 2) (i32.const 30) (i32.const 4) (i32.const 5) (i64.const 6) (i64.const 7) (i64.const 8)) + (if (i32.ne (i32.const 455)) + (then unreachable) + ) + (br 0) + ) + (unreachable) + ) +) From fbe69281ec0c3b6eadf77475bb1bee9bf3e93fce Mon Sep 17 00:00:00 2001 From: losfair Date: Mon, 19 Aug 2019 19:17:32 -0700 Subject: [PATCH 37/90] Add note on many_params test. --- examples/many_params.wat | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/many_params.wat b/examples/many_params.wat index 3794871989a..db5e4bb9be6 100644 --- a/examples/many_params.wat +++ b/examples/many_params.wat @@ -1,6 +1,7 @@ ;; Test case for correctness of reading state with the presence of parameters passed on (machine) stack. ;; Usage: Run with a backend with support for OSR. Interrupt execution randomly. ;; Should see the stack frame for `$foo` to have locals `[0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 5, [5] = 6, [6] = 7, [7] = 8` with high probability. +;; If the logic for reading stack parameters is broken, it's likely to see `[0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 5, [5] = ?, [6] = ?, [7] = ?`. (module (import "wasi_unstable" "proc_exit" (func $__wasi_proc_exit (param i32))) From 90dcdfec1cee023ea0c0d67ee25227f0154c7c47 Mon Sep 17 00:00:00 2001 From: losfair Date: Mon, 19 Aug 2019 19:17:50 -0700 Subject: [PATCH 38/90] Cargo fmt --- lib/llvm-backend/src/stackmap.rs | 7 +++++-- lib/runtime-core/src/state.rs | 14 ++++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/llvm-backend/src/stackmap.rs b/lib/llvm-backend/src/stackmap.rs index 7e4d515df2a..d2ccc3c0a03 100644 --- a/lib/llvm-backend/src/stackmap.rs +++ b/lib/llvm-backend/src/stackmap.rs @@ -1,7 +1,7 @@ // https://llvm.org/docs/StackMaps.html#stackmap-section use byteorder::{LittleEndian, ReadBytesExt}; -use std::collections::{HashMap, BTreeMap}; +use std::collections::{BTreeMap, HashMap}; use std::io::{self, Cursor}; use wasmer_runtime_core::state::{ x64::{new_machine_state, X64Register, GPR}, @@ -231,7 +231,10 @@ impl StackmapEntry { if loc.offset_or_small_constant >= 0 { assert!(loc.offset_or_small_constant >= 16); // (saved_rbp, return_address) assert!(loc.offset_or_small_constant % 8 == 0); - prev_frame_diff.insert(((loc.offset_or_small_constant as usize - 16) / 8), Some(mv)); + prev_frame_diff.insert( + ((loc.offset_or_small_constant as usize - 16) / 8), + Some(mv), + ); } else { let stack_offset = ((-loc.offset_or_small_constant) / 4) as usize; assert!( diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 580318842ff..31987fcca5e 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -217,17 +217,19 @@ impl MachineState { let prev_frame_diff: BTreeMap> = self .prev_frame .iter() - .filter(|(k, v)| if let Some(ref old_v) = old.prev_frame.get(k) { - v != old_v - } else { - true + .filter(|(k, v)| { + if let Some(ref old_v) = old.prev_frame.get(k) { + v != old_v + } else { + true + } }) .map(|(&k, v)| (k, Some(v.clone()))) .chain( old.prev_frame .iter() .filter(|(k, _)| self.prev_frame.get(k).is_none()) - .map(|(&k, _)| (k, None)) + .map(|(&k, _)| (k, None)), ) .collect(); let first_diff_wasm_stack_depth: usize = self @@ -978,7 +980,7 @@ pub mod x64 { MachineValue::WasmLocal(idx) => { wasm_locals[idx] = Some(*stack.offset(offset)); } - _ => unreachable!("values in prev frame can only be stack/local") + _ => unreachable!("values in prev frame can only be stack/local"), } } stack = stack.offset(1); // saved_rbp From bf471fbc24e1ac3bdb83ccb7a895bbe052424449 Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 21 Aug 2019 11:08:23 -0700 Subject: [PATCH 39/90] Cleanup LLVM object loader. --- lib/llvm-backend/cpp/object_loader.cpp | 265 +++++++++++-------------- lib/llvm-backend/cpp/object_loader.hh | 58 +++++- 2 files changed, 168 insertions(+), 155 deletions(-) diff --git a/lib/llvm-backend/cpp/object_loader.cpp b/lib/llvm-backend/cpp/object_loader.cpp index 18a48847bb3..c7f1d17a94c 100644 --- a/lib/llvm-backend/cpp/object_loader.cpp +++ b/lib/llvm-backend/cpp/object_loader.cpp @@ -5,179 +5,144 @@ extern "C" void __register_frame(uint8_t *); extern "C" void __deregister_frame(uint8_t *); -struct MemoryManager : llvm::RuntimeDyld::MemoryManager { -public: - MemoryManager(callbacks_t callbacks) : callbacks(callbacks) {} - - uint8_t *get_stack_map_ptr() const { return stack_map_ptr; } - - size_t get_stack_map_size() const { return stack_map_size; } - - uint8_t *get_code_ptr() const { return (uint8_t *)code_start_ptr; } +MemoryManager::~MemoryManager() { + deregisterEHFrames(); + // Deallocate all of the allocated memory. + callbacks.dealloc_memory(code_section.base, code_section.size); + callbacks.dealloc_memory(read_section.base, read_section.size); + callbacks.dealloc_memory(readwrite_section.base, readwrite_section.size); +} - size_t get_code_size() const { return code_size; } +uint8_t *MemoryManager::allocateCodeSection(uintptr_t size, unsigned alignment, + unsigned section_id, + llvm::StringRef section_name) { + return allocate_bump(code_section, code_bump_ptr, size, alignment); +} - virtual ~MemoryManager() override { - deregisterEHFrames(); - // Deallocate all of the allocated memory. - callbacks.dealloc_memory(code_section.base, code_section.size); - callbacks.dealloc_memory(read_section.base, read_section.size); - callbacks.dealloc_memory(readwrite_section.base, readwrite_section.size); +uint8_t *MemoryManager::allocateDataSection(uintptr_t size, unsigned alignment, + unsigned section_id, + llvm::StringRef section_name, + bool read_only) { + // Allocate from the read-only section or the read-write section, depending + // on if this allocation should be read-only or not. + uint8_t *ret; + if (read_only) { + ret = allocate_bump(read_section, read_bump_ptr, size, alignment); + } else { + ret = + allocate_bump(readwrite_section, readwrite_bump_ptr, size, alignment); } - - virtual uint8_t *allocateCodeSection(uintptr_t size, unsigned alignment, - unsigned section_id, - llvm::StringRef section_name) override { - return allocate_bump(code_section, code_bump_ptr, size, alignment); - } - - virtual uint8_t *allocateDataSection(uintptr_t size, unsigned alignment, - unsigned section_id, - llvm::StringRef section_name, - bool read_only) override { - // Allocate from the read-only section or the read-write section, depending - // on if this allocation should be read-only or not. - uint8_t *ret; - if (read_only) { - ret = allocate_bump(read_section, read_bump_ptr, size, alignment); - } else { - ret = - allocate_bump(readwrite_section, readwrite_bump_ptr, size, alignment); - } - if (section_name.equals(llvm::StringRef("__llvm_stackmaps")) || - section_name.equals(llvm::StringRef(".llvm_stackmaps"))) { - stack_map_ptr = ret; - stack_map_size = size; - } - return ret; + if (section_name.equals(llvm::StringRef("__llvm_stackmaps")) || + section_name.equals(llvm::StringRef(".llvm_stackmaps"))) { + stack_map_ptr = ret; + stack_map_size = size; } + return ret; +} - virtual void reserveAllocationSpace(uintptr_t code_size, uint32_t code_align, +void MemoryManager::reserveAllocationSpace(uintptr_t code_size, uint32_t code_align, uintptr_t read_data_size, uint32_t read_data_align, uintptr_t read_write_data_size, - uint32_t read_write_data_align) override { - auto aligner = [](uintptr_t ptr, size_t align) { - if (ptr == 0) { - return align; - } - return (ptr + align - 1) & ~(align - 1); - }; - - uint8_t *code_ptr_out = nullptr; - size_t code_size_out = 0; - auto code_result = - callbacks.alloc_memory(aligner(code_size, 4096), PROTECT_READ_WRITE, - &code_ptr_out, &code_size_out); - assert(code_result == RESULT_OK); - code_section = Section{code_ptr_out, code_size_out}; - code_bump_ptr = (uintptr_t)code_ptr_out; - code_start_ptr = (uintptr_t)code_ptr_out; - this->code_size = code_size; - - uint8_t *read_ptr_out = nullptr; - size_t read_size_out = 0; - auto read_result = callbacks.alloc_memory(aligner(read_data_size, 4096), - PROTECT_READ_WRITE, &read_ptr_out, - &read_size_out); - assert(read_result == RESULT_OK); - read_section = Section{read_ptr_out, read_size_out}; - read_bump_ptr = (uintptr_t)read_ptr_out; - - uint8_t *readwrite_ptr_out = nullptr; - size_t readwrite_size_out = 0; - auto readwrite_result = callbacks.alloc_memory( - aligner(read_write_data_size, 4096), PROTECT_READ_WRITE, - &readwrite_ptr_out, &readwrite_size_out); - assert(readwrite_result == RESULT_OK); - readwrite_section = Section{readwrite_ptr_out, readwrite_size_out}; - readwrite_bump_ptr = (uintptr_t)readwrite_ptr_out; - } + uint32_t read_write_data_align) { + auto aligner = [](uintptr_t ptr, size_t align) { + if (ptr == 0) { + return align; + } + return (ptr + align - 1) & ~(align - 1); + }; + uint8_t *code_ptr_out = nullptr; + size_t code_size_out = 0; + auto code_result = + callbacks.alloc_memory(aligner(code_size, 4096), PROTECT_READ_WRITE, + &code_ptr_out, &code_size_out); + assert(code_result == RESULT_OK); + code_section = Section{code_ptr_out, code_size_out}; + code_bump_ptr = (uintptr_t)code_ptr_out; + code_start_ptr = (uintptr_t)code_ptr_out; + this->code_size = code_size; + + uint8_t *read_ptr_out = nullptr; + size_t read_size_out = 0; + auto read_result = callbacks.alloc_memory(aligner(read_data_size, 4096), + PROTECT_READ_WRITE, &read_ptr_out, + &read_size_out); + assert(read_result == RESULT_OK); + read_section = Section{read_ptr_out, read_size_out}; + read_bump_ptr = (uintptr_t)read_ptr_out; + + uint8_t *readwrite_ptr_out = nullptr; + size_t readwrite_size_out = 0; + auto readwrite_result = callbacks.alloc_memory( + aligner(read_write_data_size, 4096), PROTECT_READ_WRITE, + &readwrite_ptr_out, &readwrite_size_out); + assert(readwrite_result == RESULT_OK); + readwrite_section = Section{readwrite_ptr_out, readwrite_size_out}; + readwrite_bump_ptr = (uintptr_t)readwrite_ptr_out; +} - /* Turn on the `reserveAllocationSpace` callback. */ - virtual bool needsToReserveAllocationSpace() override { return true; } +bool MemoryManager::needsToReserveAllocationSpace() { return true; } - virtual void registerEHFrames(uint8_t *addr, uint64_t LoadAddr, - size_t size) override { +void MemoryManager::registerEHFrames(uint8_t *addr, uint64_t LoadAddr, + size_t size) { // 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); + eh_frame_ptr = addr; + eh_frame_size = size; + eh_frames_registered = true; + callbacks.visit_fde(addr, size, __register_frame); #endif - } +} - virtual void deregisterEHFrames() override { +void MemoryManager::deregisterEHFrames() { // 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 + if (eh_frames_registered) { + callbacks.visit_fde(eh_frame_ptr, eh_frame_size, __deregister_frame); } +#endif +} - virtual bool finalizeMemory(std::string *ErrMsg = nullptr) override { - auto code_result = - callbacks.protect_memory(code_section.base, code_section.size, - mem_protect_t::PROTECT_READ_EXECUTE); - if (code_result != RESULT_OK) { - return false; - } - - auto read_result = callbacks.protect_memory( - read_section.base, read_section.size, mem_protect_t::PROTECT_READ); - if (read_result != RESULT_OK) { - return false; - } - - // The readwrite section is already mapped as read-write. - +bool MemoryManager::finalizeMemory(std::string *ErrMsg) { + auto code_result = + callbacks.protect_memory(code_section.base, code_section.size, + mem_protect_t::PROTECT_READ_EXECUTE); + if (code_result != RESULT_OK) { return false; } - virtual void - notifyObjectLoaded(llvm::RuntimeDyld &RTDyld, - const llvm::object::ObjectFile &Obj) override {} - -private: - struct Section { - uint8_t *base; - size_t size; - }; + auto read_result = callbacks.protect_memory( + read_section.base, read_section.size, mem_protect_t::PROTECT_READ); + if (read_result != RESULT_OK) { + return false; + } - uint8_t *allocate_bump(Section §ion, uintptr_t &bump_ptr, size_t size, - size_t align) { - auto aligner = [](uintptr_t &ptr, size_t align) { - ptr = (ptr + align - 1) & ~(align - 1); - }; + // The readwrite section is already mapped as read-write. - // Align the bump pointer to the requires alignment. - aligner(bump_ptr, align); + return false; +} - auto ret_ptr = bump_ptr; - bump_ptr += size; +void MemoryManager::notifyObjectLoaded(llvm::RuntimeDyld &RTDyld, + const llvm::object::ObjectFile &Obj) {} - assert(bump_ptr <= (uintptr_t)section.base + section.size); +uint8_t *MemoryManager::allocate_bump(Section §ion, uintptr_t &bump_ptr, size_t size, + size_t align) { + auto aligner = [](uintptr_t &ptr, size_t align) { + ptr = (ptr + align - 1) & ~(align - 1); + }; - return (uint8_t *)ret_ptr; - } + // Align the bump pointer to the requires alignment. + aligner(bump_ptr, align); - Section code_section, read_section, readwrite_section; - uintptr_t code_start_ptr; - size_t code_size; - uintptr_t code_bump_ptr, read_bump_ptr, readwrite_bump_ptr; - uint8_t *eh_frame_ptr; - size_t eh_frame_size; - bool eh_frames_registered = false; + auto ret_ptr = bump_ptr; + bump_ptr += size; - callbacks_t callbacks; + assert(bump_ptr <= (uintptr_t)section.base + section.size); - uint8_t *stack_map_ptr = nullptr; - size_t stack_map_size = 0; -}; + return (uint8_t *)ret_ptr; +} struct SymbolLookup : llvm::JITSymbolResolver { public: @@ -242,25 +207,17 @@ void *WasmModule::get_func(llvm::StringRef name) const { } uint8_t *WasmModule::get_stack_map_ptr() const { - llvm::RuntimeDyld::MemoryManager &mm = *memory_manager; - MemoryManager *local_mm = dynamic_cast(&mm); - return local_mm->get_stack_map_ptr(); + return memory_manager->get_stack_map_ptr(); } size_t WasmModule::get_stack_map_size() const { - llvm::RuntimeDyld::MemoryManager &mm = *memory_manager; - MemoryManager *local_mm = dynamic_cast(&mm); - return local_mm->get_stack_map_size(); + return memory_manager->get_stack_map_size(); } uint8_t *WasmModule::get_code_ptr() const { - llvm::RuntimeDyld::MemoryManager &mm = *memory_manager; - MemoryManager *local_mm = dynamic_cast(&mm); - return local_mm->get_code_ptr(); + return memory_manager->get_code_ptr(); } size_t WasmModule::get_code_size() const { - llvm::RuntimeDyld::MemoryManager &mm = *memory_manager; - MemoryManager *local_mm = dynamic_cast(&mm); - return local_mm->get_code_size(); + return memory_manager->get_code_size(); } diff --git a/lib/llvm-backend/cpp/object_loader.hh b/lib/llvm-backend/cpp/object_loader.hh index eb18ec600ac..1a50f58393f 100644 --- a/lib/llvm-backend/cpp/object_loader.hh +++ b/lib/llvm-backend/cpp/object_loader.hh @@ -1,3 +1,5 @@ +#pragma once + #include #include #include @@ -48,6 +50,60 @@ typedef struct { size_t data, vtable; } box_any_t; +struct MemoryManager : llvm::RuntimeDyld::MemoryManager { +public: + MemoryManager(callbacks_t callbacks) : callbacks(callbacks) {} + virtual ~MemoryManager() override; + + inline uint8_t *get_stack_map_ptr() const { return stack_map_ptr; } + inline size_t get_stack_map_size() const { return stack_map_size; } + inline uint8_t *get_code_ptr() const { return (uint8_t *)code_start_ptr; } + inline size_t get_code_size() const { return code_size; } + + virtual uint8_t *allocateCodeSection(uintptr_t size, unsigned alignment, + unsigned section_id, + llvm::StringRef section_name) override; + virtual uint8_t *allocateDataSection(uintptr_t size, unsigned alignment, + unsigned section_id, + llvm::StringRef section_name, + bool read_only) override; + virtual void reserveAllocationSpace(uintptr_t code_size, uint32_t code_align, + uintptr_t read_data_size, + uint32_t read_data_align, + uintptr_t read_write_data_size, + uint32_t read_write_data_align) override; + /* Turn on the `reserveAllocationSpace` callback. */ + virtual bool needsToReserveAllocationSpace() override; + virtual void registerEHFrames(uint8_t *addr, uint64_t LoadAddr, + size_t size) override; + virtual void deregisterEHFrames() override; + virtual bool finalizeMemory(std::string *ErrMsg = nullptr) override; + virtual void notifyObjectLoaded(llvm::RuntimeDyld &RTDyld, + const llvm::object::ObjectFile &Obj) override; + +private: + struct Section { + uint8_t *base; + size_t size; + }; + + uint8_t *allocate_bump(Section §ion, uintptr_t &bump_ptr, size_t size, + size_t align); + + Section code_section, read_section, readwrite_section; + uintptr_t code_start_ptr; + size_t code_size; + uintptr_t code_bump_ptr, read_bump_ptr, readwrite_bump_ptr; + uint8_t *eh_frame_ptr; + size_t eh_frame_size; + bool eh_frames_registered = false; + + callbacks_t callbacks; + + uint8_t *stack_map_ptr = nullptr; + size_t stack_map_size = 0; +}; + struct WasmException { public: virtual std::string description() const noexcept = 0; @@ -97,7 +153,7 @@ public: bool _init_failed = false; private: - std::unique_ptr memory_manager; + std::unique_ptr memory_manager; std::unique_ptr object_file; std::unique_ptr runtime_dyld; }; From bf9d915635e206f12446fc0a2d964da2be63e39c Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 21 Aug 2019 14:53:33 -0700 Subject: [PATCH 40/90] Fix a few issues from PR comments. --- lib/llvm-backend/src/backend.rs | 32 +-- lib/runtime-core/src/loader.rs | 4 +- lib/runtime-core/src/state.rs | 26 +-- lib/runtime-core/src/tiering.rs | 264 +++++++++++----------- lib/singlepass-backend/src/codegen_x64.rs | 4 +- src/bin/wasmer.rs | 4 +- 6 files changed, 161 insertions(+), 173 deletions(-) diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index 51284ccb8cb..f49cb9f149c 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -70,6 +70,8 @@ extern "C" { ) -> bool; } +static SIGNAL_HANDLER_INSTALLED: Once = Once::new(); + fn get_callbacks() -> Callbacks { extern "C" fn alloc_memory( size: usize, @@ -218,16 +220,6 @@ impl LLVMBackend { ) }; - // Uncomment this to make spectests pass. - // TODO: fix this - /* - - static SIGNAL_HANDLER_INSTALLED: Once = Once::new(); - - SIGNAL_HANDLER_INSTALLED.call_once(|| unsafe { - crate::platform::install_signal_handler(); - });*/ - if res != LLVMResult::OK { panic!("failed to load object") } @@ -235,7 +227,7 @@ impl LLVMBackend { let buffer = Arc::new(Buffer::LlvmMemory(memory_buffer)); let raw_stackmap = unsafe { - ::std::slice::from_raw_parts( + std::slice::from_raw_parts( llvm_backend_get_stack_map_ptr(module), llvm_backend_get_stack_map_size(module), ) @@ -281,8 +273,8 @@ impl LLVMBackend { let mut map_records: BTreeMap = BTreeMap::new(); - for r in &map.stk_map_records { - map_records.insert(r.patchpoint_id as usize, r); + for record in &map.stk_map_records { + map_records.insert(record.patchpoint_id as usize, record); } for ((start_id, start_entry), (end_id, end_entry)) in stackmaps @@ -314,7 +306,7 @@ impl LLVMBackend { &mut msm, ); } else { - // TODO: optimized out? + // The record is optimized out. } } @@ -329,8 +321,6 @@ impl LLVMBackend { }) .collect(); - //println!("MSM: {:?}", msm); - ( Self { module, @@ -341,7 +331,7 @@ impl LLVMBackend { LLVMCache { buffer }, ) } else { - eprintln!("WARNING: No stack map"); + // This module contains no functions so no stackmaps. ( Self { module, @@ -366,8 +356,6 @@ impl LLVMBackend { return Err("failed to load object".to_string()); } - static SIGNAL_HANDLER_INSTALLED: Once = Once::new(); - SIGNAL_HANDLER_INSTALLED.call_once(|| { crate::platform::install_signal_handler(); }); @@ -431,12 +419,16 @@ impl RunnableModule for LLVMBackend { mem::transmute(symbol) }; + SIGNAL_HANDLER_INSTALLED.call_once(|| unsafe { + crate::platform::install_signal_handler(); + }); + Some(unsafe { Wasm::from_raw_parts(trampoline, invoke_trampoline, None) }) } fn get_code(&self) -> Option<&[u8]> { Some(unsafe { - ::std::slice::from_raw_parts( + std::slice::from_raw_parts( llvm_backend_get_code_ptr(self.module), llvm_backend_get_code_size(self.module), ) diff --git a/lib/runtime-core/src/loader.rs b/lib/runtime-core/src/loader.rs index 4b2c303eace..935d201a460 100644 --- a/lib/runtime-core/src/loader.rs +++ b/lib/runtime-core/src/loader.rs @@ -185,12 +185,12 @@ impl Drop for CodeMemory { impl Deref for CodeMemory { type Target = [u8]; fn deref(&self) -> &[u8] { - unsafe { ::std::slice::from_raw_parts(self.ptr, self.size) } + unsafe { std::slice::from_raw_parts(self.ptr, self.size) } } } impl DerefMut for CodeMemory { fn deref_mut(&mut self) -> &mut [u8] { - unsafe { ::std::slice::from_raw_parts_mut(self.ptr, self.size) } + unsafe { std::slice::from_raw_parts_mut(self.ptr, self.size) } } } diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 31987fcca5e..39cd6b89751 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -154,7 +154,6 @@ impl ModuleStateMap { self.lookup_ip(ip, base, |fsm| &fsm.call_offsets) } - #[warn(dead_code)] pub fn lookup_trappable_ip( &self, ip: usize, @@ -163,7 +162,6 @@ impl ModuleStateMap { self.lookup_ip(ip, base, |fsm| &fsm.trappable_offsets) } - #[warn(dead_code)] pub fn lookup_loop_ip( &self, ip: usize, @@ -535,30 +533,30 @@ pub mod x64 { match inner.0 { MachineValue::WasmStack(x) => match state.wasm_stack[x] { WasmAbstractValue::Const(x) => { - assert!(x <= ::std::u32::MAX as u64); + assert!(x <= std::u32::MAX as u64); stack[stack_offset] |= x; } WasmAbstractValue::Runtime => { let v = f.stack[x].unwrap(); - assert!(v <= ::std::u32::MAX as u64); + assert!(v <= std::u32::MAX as u64); stack[stack_offset] |= v; } }, MachineValue::WasmLocal(x) => match fsm.locals[x] { WasmAbstractValue::Const(x) => { - assert!(x <= ::std::u32::MAX as u64); + assert!(x <= std::u32::MAX as u64); stack[stack_offset] |= x; } WasmAbstractValue::Runtime => { let v = f.locals[x].unwrap(); - assert!(v <= ::std::u32::MAX as u64); + assert!(v <= std::u32::MAX as u64); stack[stack_offset] |= v; } }, MachineValue::VmctxDeref(ref seq) => { stack[stack_offset] |= compute_vmctx_deref(vmctx as *const Ctx, seq) - & (::std::u32::MAX as u64); + & (std::u32::MAX as u64); } MachineValue::Undefined => {} _ => unimplemented!("TwoHalves.0"), @@ -566,30 +564,30 @@ pub mod x64 { match inner.1 { MachineValue::WasmStack(x) => match state.wasm_stack[x] { WasmAbstractValue::Const(x) => { - assert!(x <= ::std::u32::MAX as u64); + assert!(x <= std::u32::MAX as u64); stack[stack_offset] |= x << 32; } WasmAbstractValue::Runtime => { let v = f.stack[x].unwrap(); - assert!(v <= ::std::u32::MAX as u64); + assert!(v <= std::u32::MAX as u64); stack[stack_offset] |= v << 32; } }, MachineValue::WasmLocal(x) => match fsm.locals[x] { WasmAbstractValue::Const(x) => { - assert!(x <= ::std::u32::MAX as u64); + assert!(x <= std::u32::MAX as u64); stack[stack_offset] |= x << 32; } WasmAbstractValue::Runtime => { let v = f.locals[x].unwrap(); - assert!(v <= ::std::u32::MAX as u64); + assert!(v <= std::u32::MAX as u64); stack[stack_offset] |= v << 32; } }, MachineValue::VmctxDeref(ref seq) => { stack[stack_offset] |= (compute_vmctx_deref(vmctx as *const Ctx, seq) - & (::std::u32::MAX as u64)) + & (std::u32::MAX as u64)) << 32; } MachineValue::Undefined => {} @@ -728,7 +726,7 @@ pub mod x64 { assert_eq!(vmctx.internal.memory_bound, memory.len()); } - ::std::slice::from_raw_parts_mut( + std::slice::from_raw_parts_mut( vmctx.internal.memory_base, vmctx.internal.memory_bound, ) @@ -763,7 +761,7 @@ pub mod x64 { None } else { Some( - ::std::slice::from_raw_parts( + std::slice::from_raw_parts( vmctx.internal.memory_base, vmctx.internal.memory_bound, ) diff --git a/lib/runtime-core/src/tiering.rs b/lib/runtime-core/src/tiering.rs index 4c5b8505509..5980ac14606 100644 --- a/lib/runtime-core/src/tiering.rs +++ b/lib/runtime-core/src/tiering.rs @@ -70,7 +70,7 @@ unsafe fn do_optimize( } } -pub fn run_tiering ShellExitOperation>( +pub unsafe fn run_tiering ShellExitOperation>( module_info: &ModuleInfo, wasm_binary: &[u8], mut resume_image: Option, @@ -80,157 +80,155 @@ pub fn run_tiering ShellExitOperation>( optimized_backends: Vec Box + Send>>, interactive_shell: F, ) -> Result<(), String> { - unsafe { - ensure_sighandler(); - - let ctx_box = Arc::new(Mutex::new(CtxWrapper(baseline.context_mut() as *mut _))); - // Ensure that the ctx pointer's lifetime is not longer than Instance's. - let _deferred_ctx_box_cleanup: Defer<_> = { - let ctx_box = ctx_box.clone(); - Defer(Some(move || { - ctx_box.lock().unwrap().0 = ::std::ptr::null_mut(); - })) - }; - let opt_state = Arc::new(OptimizationState { - outcome: Mutex::new(None), + ensure_sighandler(); + + let ctx_box = Arc::new(Mutex::new(CtxWrapper(baseline.context_mut() as *mut _))); + // Ensure that the ctx pointer's lifetime is not longer than Instance's. + let _deferred_ctx_box_cleanup: Defer<_> = { + let ctx_box = ctx_box.clone(); + Defer(Some(move || { + ctx_box.lock().unwrap().0 = ::std::ptr::null_mut(); + })) + }; + let opt_state = Arc::new(OptimizationState { + outcome: Mutex::new(None), + }); + + { + let wasm_binary = wasm_binary.to_vec(); + let ctx_box = ctx_box.clone(); + let opt_state = opt_state.clone(); + ::std::thread::spawn(move || { + for backend in optimized_backends { + if !ctx_box.lock().unwrap().0.is_null() { + do_optimize(&wasm_binary, backend(), &ctx_box, &opt_state); + } + } }); + } - { - let wasm_binary = wasm_binary.to_vec(); - let ctx_box = ctx_box.clone(); - let opt_state = opt_state.clone(); - ::std::thread::spawn(move || { - for backend in optimized_backends { - if !ctx_box.lock().unwrap().0.is_null() { - do_optimize(&wasm_binary, backend(), &ctx_box, &opt_state); - } - } - }); + let mut optimized_instances: Vec = vec![]; + + push_code_version(CodeVersion { + baseline: true, + msm: baseline + .module + .runnable_module + .get_module_state_map() + .unwrap(), + base: baseline.module.runnable_module.get_code().unwrap().as_ptr() as usize, + }); + let n_versions: Cell = Cell::new(1); + + let _deferred_pop_versions = Defer(Some(|| { + for _ in 0..n_versions.get() { + pop_code_version().unwrap(); } + })); - let mut optimized_instances: Vec = vec![]; - - push_code_version(CodeVersion { - baseline: true, - msm: baseline + loop { + let new_optimized: Option<&mut Instance> = { + let mut outcome = opt_state.outcome.lock().unwrap(); + if let Some(x) = outcome.take() { + let instance = x + .module + .instantiate(&import_object) + .map_err(|e| format!("Can't instantiate module: {:?}", e))?; + // Keep the optimized code alive. + optimized_instances.push(instance); + optimized_instances.last_mut() + } else { + None + } + }; + if let Some(optimized) = new_optimized { + let base = module_info.imported_functions.len(); + let code_ptr = optimized .module .runnable_module - .get_module_state_map() - .unwrap(), - base: baseline.module.runnable_module.get_code().unwrap().as_ptr() as usize, - }); - let n_versions: Cell = Cell::new(1); - - let _deferred_pop_versions = Defer(Some(|| { - for _ in 0..n_versions.get() { - pop_code_version().unwrap(); + .get_code() + .unwrap() + .as_ptr() as usize; + let target_addresses: Vec = optimized + .module + .runnable_module + .get_local_function_offsets() + .unwrap() + .into_iter() + .map(|x| code_ptr + x) + .collect(); + assert_eq!(target_addresses.len(), module_info.func_assoc.len() - base); + for i in base..module_info.func_assoc.len() { + baseline + .module + .runnable_module + .patch_local_function(i - base, target_addresses[i - base]); } - })); - - loop { - let new_optimized: Option<&mut Instance> = { - let mut outcome = opt_state.outcome.lock().unwrap(); - if let Some(x) = outcome.take() { - let instance = x - .module - .instantiate(&import_object) - .map_err(|e| format!("Can't instantiate module: {:?}", e))?; - // Keep the optimized code alive. - optimized_instances.push(instance); - optimized_instances.last_mut() - } else { - None - } - }; - if let Some(optimized) = new_optimized { - let base = module_info.imported_functions.len(); - let code_ptr = optimized + + push_code_version(CodeVersion { + baseline: false, + msm: optimized .module .runnable_module - .get_code() - .unwrap() - .as_ptr() as usize; - let target_addresses: Vec = optimized + .get_module_state_map() + .unwrap(), + base: optimized .module .runnable_module - .get_local_function_offsets() + .get_code() .unwrap() - .into_iter() - .map(|x| code_ptr + x) - .collect(); - assert_eq!(target_addresses.len(), module_info.func_assoc.len() - base); - for i in base..module_info.func_assoc.len() { - baseline - .module - .runnable_module - .patch_local_function(i - base, target_addresses[i - base]); - } - - push_code_version(CodeVersion { - baseline: false, - msm: optimized - .module - .runnable_module - .get_module_state_map() - .unwrap(), - base: optimized - .module - .runnable_module - .get_code() - .unwrap() - .as_ptr() as usize, - }); - n_versions.set(n_versions.get() + 1); + .as_ptr() as usize, + }); + n_versions.set(n_versions.get() + 1); - baseline.context_mut().local_functions = optimized.context_mut().local_functions; + baseline.context_mut().local_functions = optimized.context_mut().local_functions; + } + // Assuming we do not want to do breakpoint-based debugging on optimized backends. + let breakpoints = baseline.module.runnable_module.get_breakpoints(); + let ctx = baseline.context_mut() as *mut _; + let ret = with_ctx(ctx, || { + if let Some(image) = resume_image.take() { + let msm = baseline + .module + .runnable_module + .get_module_state_map() + .unwrap(); + let code_base = + baseline.module.runnable_module.get_code().unwrap().as_ptr() as usize; + invoke_call_return_on_stack( + &msm, + code_base, + image, + baseline.context_mut(), + breakpoints.clone(), + ) + .map(|_| ()) + } else { + catch_unsafe_unwind(|| start_raw(baseline.context_mut()), breakpoints.clone()) } - // Assuming we do not want to do breakpoint-based debugging on optimized backends. - let breakpoints = baseline.module.runnable_module.get_breakpoints(); - let ctx = baseline.context_mut() as *mut _; - let ret = with_ctx(ctx, || { - if let Some(image) = resume_image.take() { - let msm = baseline - .module - .runnable_module - .get_module_state_map() - .unwrap(); - let code_base = - baseline.module.runnable_module.get_code().unwrap().as_ptr() as usize; - invoke_call_return_on_stack( - &msm, - code_base, - image, - baseline.context_mut(), - breakpoints.clone(), - ) - .map(|_| ()) - } else { - catch_unsafe_unwind(|| start_raw(baseline.context_mut()), breakpoints.clone()) + }); + if let Err(e) = ret { + if let Ok(new_image) = e.downcast::() { + // Tier switch event + if !was_sigint_triggered_fault() && opt_state.outcome.lock().unwrap().is_some() + { + resume_image = Some(*new_image); + continue; } - }); - if let Err(e) = ret { - if let Ok(new_image) = e.downcast::() { - // Tier switch event - if !was_sigint_triggered_fault() && opt_state.outcome.lock().unwrap().is_some() - { - resume_image = Some(*new_image); - continue; - } - let op = interactive_shell(InteractiveShellContext { - image: Some(*new_image), - patched: n_versions.get() > 1, - }); - match op { - ShellExitOperation::ContinueWith(new_image) => { - resume_image = Some(new_image); - } + let op = interactive_shell(InteractiveShellContext { + image: Some(*new_image), + patched: n_versions.get() > 1, + }); + match op { + ShellExitOperation::ContinueWith(new_image) => { + resume_image = Some(new_image); } - } else { - return Err("Error while executing WebAssembly".into()); } } else { - return Ok(()); + return Err("Error while executing WebAssembly".into()); } + } else { + return Ok(()); } } } diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 8e8bb13ff88..7f966eaa5ab 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -277,7 +277,7 @@ impl RunnableModule for X64ExecutionContext { let execution_context = ::std::mem::transmute_copy::<&dyn RunnableModule, &X64ExecutionContext>(&&**rm); - let args = ::std::slice::from_raw_parts( + let args = std::slice::from_raw_parts( args, num_params_plus_one.unwrap().as_ptr() as usize - 1, ); @@ -1690,7 +1690,7 @@ impl FunctionCodeGenerator for X64FunctionCode { let start_label = a.get_label(); // skip the patchpoint during normal execution a.emit_jmp(Condition::None, start_label); - // patchpoint of 32 bytes + // patchpoint of 32 1-byte nops for _ in 0..32 { a.emit_nop(); } diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 3a8c4394998..aedb3ecc359 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -587,7 +587,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { let start_raw: extern "C" fn(&mut wasmer_runtime_core::vm::Ctx) = unsafe { ::std::mem::transmute(start.get_vm_func()) }; - run_tiering( + unsafe { run_tiering( module.info(), &wasm_binary, if let Some(ref path) = options.resume { @@ -612,7 +612,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { }) .collect(), interactive_shell, - )?; + )? }; } #[cfg(not(feature = "managed"))] From 08ab8d16e12dd8edcdd90633aabfb16df53074ca Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 21 Aug 2019 15:05:10 -0700 Subject: [PATCH 41/90] Handle SIGILL in LLVM. --- lib/llvm-backend/src/platform/unix.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/llvm-backend/src/platform/unix.rs b/lib/llvm-backend/src/platform/unix.rs index a07afa13042..b06746d9e00 100644 --- a/lib/llvm-backend/src/platform/unix.rs +++ b/lib/llvm-backend/src/platform/unix.rs @@ -4,7 +4,7 @@ use libc::{ 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 nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, SIGBUS, SIGSEGV, SIGILL}; use std::ptr; /// `__register_frame` and `__deregister_frame` on macos take a single fde as an @@ -57,6 +57,7 @@ pub unsafe fn install_signal_handler() { ); sigaction(SIGSEGV, &sa).unwrap(); sigaction(SIGBUS, &sa).unwrap(); + sigaction(SIGILL, &sa).unwrap(); } #[cfg_attr(nightly, unwind(allowed))] From 6d7a91a2711e65019b093a7b9794bd2b972a572c Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 21 Aug 2019 15:10:27 -0700 Subject: [PATCH 42/90] Remove a.out in lib/runtime-c-api/tests. --- cranelift | 1 + lib/runtime-c-api/tests/a.out | Bin 14996 -> 0 bytes 2 files changed, 1 insertion(+) create mode 160000 cranelift delete mode 100755 lib/runtime-c-api/tests/a.out diff --git a/cranelift b/cranelift new file mode 160000 index 00000000000..cb62a1ead2c --- /dev/null +++ b/cranelift @@ -0,0 +1 @@ +Subproject commit cb62a1ead2c5346ccb0f1224ecae5939ac064f87 diff --git a/lib/runtime-c-api/tests/a.out b/lib/runtime-c-api/tests/a.out deleted file mode 100755 index 171b88eff996dc44864b97d442a2290bf08dd8d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14996 zcmeHOeQcH089!I7tJTt?;Mk_@0v4+Q3Q85x#uj_!C6w7I3_@n!-roC`R_@pC2Ok=? zx_XnoUhZrh82&KYESsWph8Rj}LtVj!RyF|%(QYvY3F>XaHgt>W$U^t~opWw``?i4p zEm`hK&w0L|bIxL0D~)UM7xV@n+C0GefY zk%Amot}l$SRjQz2YzhIFD^=N6gWiaV?Y&2cYH&EF*{Ekg-w7DM4@(324Z!PBS+dVB z<3XR8+GR`RULk6xkWL5Bjd~+$MIsih2(&a-_;&>Spjq&k%5nVj{H&)h{-&zqSH5W% zcCCEZe>eDUR2Qn4j!B~umuoZai0dxkrIhJXj`?#w?wMJRg6y{$m9pG*s8}DfqOppn zns-#xN5fBAzId!+n>QA;q7`v(bh8z&h*|;58?!3>RwTwzE2$YxgyJnh%k-JvNXuf( zq@|HPu^+}e+mGwwIlR7H<8y}I<2zz;E4X;&xRnqKV8eL~VI3G_t_5kXOTOeIkdHt< z0{IB!Ban|kJ_7j&ka#JqwRe4(muo9Ibzs}3q~q2lA7Lj*kw-# z3i4iXGYZ{WXn$p|J*SCM5@(Fm&WwFD^D}%ZGi=Wg$e~O-2-|a7;#-wqaKO{g;iNqM z4|vX$q!$A>Ql7!o+H=#^_8YzrtDjp|YWO_;MtatUVtn{+Uv>?2+xlF#r+@h9=;-Lt zf;HfaRN{1M{TU-&_5AhlkS@Lp%>5#B7@zcy7LahI)}OX#%?AcOd)6Eva*Uq7Odpg| zrS`1p`PE~vYUdH(qh&sIA#mi#wSxjgOp_0$(K0M`Q+Hi z*-Dcja|>8YPuU+WJq1DOxQonJ*lj(`)nN5fy-Ko2S*F>Co!m>8??O#?0tX#ry+T&H z>Q;=HGvEh5G9mbppT{Q-7Hy7KoD6!!!4 zcp=GrhP^q=F?D0%g*}jAVieOEf$>1{Uuc=AN~MWmiO9AKF>4N2(*|BL*THJ(`$jsM zpq?fL4xmM64FH*6V0iWJBW#sY@>B3K0g0ZGN^GI@rBW(oXTDxC zv8}0l9uFOcIYhNoFF~q{;>;qdrn;mcUDXYHJGl-5baf0iZN2QCD|Do$^=quqS+3AA zyi<*~i%_kHbZmugfHhX=dI^em0`$ZX`piRcBvpvwo>;naZ*dTZ+@KE5HC^>l8@SSA9#~gJkM=vW!FVN8rIy#L; zO?Bsf*X8HwRpzELZ=?BBG~bgo$1E95?1Fx<_>RZ>l{1}-kwUmj313sfb~{;1;Tt5= zRjo?+oD|9}j~6)QZz;|QaYN!&1JE^64;iVoBgXwFN|H=|BgoJ6^Vodiz0CEXOK#{G zEqfJ;qh~Pek9u=+5T0wpUC!8*`AT@S+qRUZ~F@ZUGw;8+53PU%_qPd z{sOO`=C6r;LTmWR(AD2E>*#^Db?NQ^oC;k$_~Bvwvr1+h8ARuP*? zjCUu)MZ_A231UHF-(b<3xygpl6Kf}Sme`BL`2K1BEwSUo-X_*htdCd^u+<@V1ebYn zTslSu{sosdvOaP{li;0 z7-lgWu!}gku(|C8WX;OPVYvfmD~Dl4?arErWQ>vbIoAPa=*? z4vCE*g2?@ZeWV&lSwUZ92dQR7A^Sxt0!rqKnn-O2rBXknT3w1n-iTzoYeu!qR#{O~ zWxP!0Voblv+)$(e>8o&rVEffqVr^^JKK@LME}+~dsg z+++y^+27&Z0XayT$x?|nmuAvEm)_){8y$3ugN`_8-j(J0+v%X6ba{k(&I-9h&|X#OTk{i*)`?x4%D za=G$)2ffun?{(0J6^&MvLI7Te@rsPUb-))*1b^F6g34Vr1NA0Uq_PFJl$eFeJ@#Ex z{w9LIbNN0h)7wbdG94}Epz;iJqs~R0hdLkicGNP|1*qJI`q`*P8eRTI;(s*`H-7yy z`MJhfhN~8JPVsz#l9_X?PB@ Date: Wed, 21 Aug 2019 15:23:11 -0700 Subject: [PATCH 43/90] Disable LLVM stackmap on Windows --- lib/llvm-backend/src/backend.rs | 207 ++++++++++++++++--------------- lib/llvm-backend/src/stackmap.rs | 15 +-- 2 files changed, 113 insertions(+), 109 deletions(-) diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index f49cb9f149c..901730ae6f3 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -226,122 +226,125 @@ impl LLVMBackend { let buffer = Arc::new(Buffer::LlvmMemory(memory_buffer)); - let raw_stackmap = unsafe { - std::slice::from_raw_parts( - llvm_backend_get_stack_map_ptr(module), - llvm_backend_get_stack_map_size(module), - ) - }; - if raw_stackmap.len() > 0 { - let map = stackmap::StackMap::parse(raw_stackmap).unwrap(); - - let (code_ptr, code_size) = unsafe { - ( - llvm_backend_get_code_ptr(module), - llvm_backend_get_code_size(module), + #[cfg(all(any(target_os = "linux", target_os = "macos"), target_arch = "x86_64"))] + { + let raw_stackmap = unsafe { + std::slice::from_raw_parts( + llvm_backend_get_stack_map_ptr(module), + llvm_backend_get_stack_map_size(module), ) }; - let mut msm = ModuleStateMap { - local_functions: Default::default(), - total_size: code_size, - }; + if raw_stackmap.len() > 0 { + let map = stackmap::StackMap::parse(raw_stackmap).unwrap(); + + let (code_ptr, code_size) = unsafe { + ( + llvm_backend_get_code_ptr(module), + llvm_backend_get_code_size(module), + ) + }; + let mut msm = ModuleStateMap { + local_functions: Default::default(), + total_size: code_size, + }; - let num_local_functions = - module_info.func_assoc.len() - module_info.imported_functions.len(); - let mut local_func_id_to_addr: Vec = Vec::with_capacity(num_local_functions); + let num_local_functions = + module_info.func_assoc.len() - module_info.imported_functions.len(); + let mut local_func_id_to_addr: Vec = Vec::with_capacity(num_local_functions); - // All local functions. - for index in module_info.imported_functions.len()..module_info.func_assoc.len() { - let name = if cfg!(target_os = "macos") { - format!("_fn{}", index) - } else { - format!("fn{}", index) - }; + // All local functions. + for index in module_info.imported_functions.len()..module_info.func_assoc.len() { + let name = if cfg!(target_os = "macos") { + format!("_fn{}", index) + } else { + format!("fn{}", index) + }; - let c_str = CString::new(name).unwrap(); - let ptr = unsafe { get_func_symbol(module, c_str.as_ptr()) }; + let c_str = CString::new(name).unwrap(); + let ptr = unsafe { get_func_symbol(module, c_str.as_ptr()) }; - assert!(!ptr.is_null()); - local_func_id_to_addr.push(ptr as usize); - } + assert!(!ptr.is_null()); + local_func_id_to_addr.push(ptr as usize); + } - let mut addr_to_size_record: BTreeMap = BTreeMap::new(); + let mut addr_to_size_record: BTreeMap = BTreeMap::new(); - for record in &map.stk_size_records { - addr_to_size_record.insert(record.function_address as usize, record); - } + for record in &map.stk_size_records { + addr_to_size_record.insert(record.function_address as usize, record); + } - let mut map_records: BTreeMap = BTreeMap::new(); + let mut map_records: BTreeMap = BTreeMap::new(); - for record in &map.stk_map_records { - map_records.insert(record.patchpoint_id as usize, record); - } + for record in &map.stk_map_records { + map_records.insert(record.patchpoint_id as usize, record); + } - for ((start_id, start_entry), (end_id, end_entry)) in stackmaps - .entries - .iter() - .enumerate() - .step_by(2) - .zip(stackmaps.entries.iter().enumerate().skip(1).step_by(2)) - { - if let Some(map_record) = map_records.get(&start_id) { - assert_eq!(start_id, map_record.patchpoint_id as usize); - assert!(start_entry.is_start); - assert!(!end_entry.is_start); - - let end_record = map_records.get(&end_id); - - let addr = local_func_id_to_addr[start_entry.local_function_id]; - let size_record = *addr_to_size_record - .get(&addr) - .expect("size_record not found"); - - start_entry.populate_msm( - module_info, - code_ptr as usize, - &map, - size_record, - map_record, - end_record.map(|x| (end_entry, *x)), - &mut msm, - ); - } else { - // The record is optimized out. + for ((start_id, start_entry), (end_id, end_entry)) in stackmaps + .entries + .iter() + .enumerate() + .step_by(2) + .zip(stackmaps.entries.iter().enumerate().skip(1).step_by(2)) + { + if let Some(map_record) = map_records.get(&start_id) { + assert_eq!(start_id, map_record.patchpoint_id as usize); + assert!(start_entry.is_start); + assert!(!end_entry.is_start); + + let end_record = map_records.get(&end_id); + + let addr = local_func_id_to_addr[start_entry.local_function_id]; + let size_record = *addr_to_size_record + .get(&addr) + .expect("size_record not found"); + + start_entry.populate_msm( + module_info, + code_ptr as usize, + &map, + size_record, + map_record, + end_record.map(|x| (end_entry, *x)), + &mut msm, + ); + } else { + // The record is optimized out. + } } - } - let code_ptr = unsafe { llvm_backend_get_code_ptr(module) } as usize; - let code_len = unsafe { llvm_backend_get_code_size(module) } as usize; - - let local_func_id_to_offset: Vec = local_func_id_to_addr - .iter() - .map(|&x| { - assert!(x >= code_ptr && x < code_ptr + code_len); - x - code_ptr - }) - .collect(); - - ( - Self { - module, - buffer: Arc::clone(&buffer), - msm: Some(msm), - local_func_id_to_offset, - }, - LLVMCache { buffer }, - ) - } else { - // This module contains no functions so no stackmaps. - ( - Self { - module, - buffer: Arc::clone(&buffer), - msm: None, - local_func_id_to_offset: vec![], - }, - LLVMCache { buffer }, - ) + let code_ptr = unsafe { llvm_backend_get_code_ptr(module) } as usize; + let code_len = unsafe { llvm_backend_get_code_size(module) } as usize; + + let local_func_id_to_offset: Vec = local_func_id_to_addr + .iter() + .map(|&x| { + assert!(x >= code_ptr && x < code_ptr + code_len); + x - code_ptr + }) + .collect(); + + return ( + Self { + module, + buffer: Arc::clone(&buffer), + msm: Some(msm), + local_func_id_to_offset, + }, + LLVMCache { buffer }, + ) + } } + + // Stackmap is not supported on this platform, or this module contains no functions so no stackmaps. + ( + Self { + module, + buffer: Arc::clone(&buffer), + msm: None, + local_func_id_to_offset: vec![], + }, + LLVMCache { buffer }, + ) } pub unsafe fn from_buffer(memory: Memory) -> Result<(Self, LLVMCache), String> { diff --git a/lib/llvm-backend/src/stackmap.rs b/lib/llvm-backend/src/stackmap.rs index d2ccc3c0a03..f409d719ef2 100644 --- a/lib/llvm-backend/src/stackmap.rs +++ b/lib/llvm-backend/src/stackmap.rs @@ -3,11 +3,6 @@ use byteorder::{LittleEndian, ReadBytesExt}; use std::collections::{BTreeMap, HashMap}; use std::io::{self, Cursor}; -use wasmer_runtime_core::state::{ - x64::{new_machine_state, X64Register, GPR}, - FunctionStateMap, MachineStateDiff, MachineValue, ModuleStateMap, OffsetInfo, RegisterIndex, - SuspendOffset, WasmAbstractValue, -}; use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::{ module::ModuleInfo, @@ -87,6 +82,7 @@ pub struct MachineStateDiff { */ impl StackmapEntry { + #[cfg(all(any(target_os = "linux", target_os = "macos"), target_arch = "x86_64"))] pub fn populate_msm( &self, module_info: &ModuleInfo, @@ -95,8 +91,13 @@ impl StackmapEntry { size_record: &StkSizeRecord, map_record: &StkMapRecord, end: Option<(&StackmapEntry, &StkMapRecord)>, - msm: &mut ModuleStateMap, + msm: &mut wasmer_runtime_core::state::ModuleStateMap, ) { + use wasmer_runtime_core::state::{ + x64::{new_machine_state, X64Register, GPR}, + FunctionStateMap, MachineStateDiff, MachineValue, OffsetInfo, RegisterIndex, + SuspendOffset, WasmAbstractValue, + }; let func_base_addr = (size_record.function_address as usize) .checked_sub(code_addr) .unwrap(); @@ -232,7 +233,7 @@ impl StackmapEntry { assert!(loc.offset_or_small_constant >= 16); // (saved_rbp, return_address) assert!(loc.offset_or_small_constant % 8 == 0); prev_frame_diff.insert( - ((loc.offset_or_small_constant as usize - 16) / 8), + (loc.offset_or_small_constant as usize - 16) / 8, Some(mv), ); } else { From 56e735349d1e2f11c85efba5964184c0beab9d96 Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 21 Aug 2019 15:23:56 -0700 Subject: [PATCH 44/90] Format everything --- lib/llvm-backend/cpp/object_loader.cpp | 95 +++++++++++++------------- lib/llvm-backend/cpp/object_loader.hh | 16 +++-- lib/llvm-backend/src/backend.rs | 2 +- lib/llvm-backend/src/platform/unix.rs | 4 +- lib/llvm-backend/src/stackmap.rs | 6 +- lib/runtime-core/src/state.rs | 7 +- lib/runtime-core/src/tiering.rs | 3 +- src/bin/wasmer.rs | 54 ++++++++------- 8 files changed, 92 insertions(+), 95 deletions(-) diff --git a/lib/llvm-backend/cpp/object_loader.cpp b/lib/llvm-backend/cpp/object_loader.cpp index 49590efda2f..1e842b97e5a 100644 --- a/lib/llvm-backend/cpp/object_loader.cpp +++ b/lib/llvm-backend/cpp/object_loader.cpp @@ -6,7 +6,7 @@ extern "C" void __register_frame(uint8_t *); extern "C" void __deregister_frame(uint8_t *); -MemoryManager::~MemoryManager() { +MemoryManager::~MemoryManager() { deregisterEHFrames(); // Deallocate all of the allocated memory. callbacks.dealloc_memory(code_section.base, code_section.size); @@ -14,72 +14,68 @@ MemoryManager::~MemoryManager() { callbacks.dealloc_memory(readwrite_section.base, readwrite_section.size); } void unwinding_setjmp(jmp_buf stack_out, void (*func)(void *), void *userdata) { - if(setjmp(stack_out)) { + if (setjmp(stack_out)) { } else { func(userdata); } } -[[noreturn]] -void unwinding_longjmp(jmp_buf stack_in) { - longjmp(stack_in, 42); -} +[[noreturn]] void unwinding_longjmp(jmp_buf stack_in) { longjmp(stack_in, 42); } struct UnwindPoint { - UnwindPoint *prev; - jmp_buf stack; - std::function *f; - std::unique_ptr exception; + UnwindPoint *prev; + jmp_buf stack; + std::function *f; + std::unique_ptr exception; }; static thread_local UnwindPoint *unwind_state = nullptr; static void unwind_payload(void *_point) { - UnwindPoint *point = (UnwindPoint *) _point; - (*point->f)(); + UnwindPoint *point = (UnwindPoint *)_point; + (*point->f)(); } -void catch_unwind(std::function&& f) { - UnwindPoint current; - current.prev = unwind_state; - current.f = &f; - unwind_state = ¤t; +void catch_unwind(std::function &&f) { + UnwindPoint current; + current.prev = unwind_state; + current.f = &f; + unwind_state = ¤t; - unwinding_setjmp(current.stack, unwind_payload, (void *) ¤t); - if(current.exception) { - throw *current.exception; - } + unwinding_setjmp(current.stack, unwind_payload, (void *)¤t); + if (current.exception) { + throw *current.exception; + } } void unsafe_unwind(std::exception *exception) { - UnwindPoint *state = unwind_state; - if(state) { - state->exception.reset(exception); - unwinding_longjmp(state->stack); - } else { - abort(); - } + UnwindPoint *state = unwind_state; + if (state) { + state->exception.reset(exception); + unwinding_longjmp(state->stack); + } else { + abort(); + } } uint8_t *MemoryManager::allocateCodeSection(uintptr_t size, unsigned alignment, - unsigned section_id, - llvm::StringRef section_name) { + unsigned section_id, + llvm::StringRef section_name) { return allocate_bump(code_section, code_bump_ptr, size, alignment); } uint8_t *MemoryManager::allocateDataSection(uintptr_t size, unsigned alignment, - unsigned section_id, - llvm::StringRef section_name, - bool read_only) { + unsigned section_id, + llvm::StringRef section_name, + bool read_only) { // Allocate from the read-only section or the read-write section, depending // on if this allocation should be read-only or not. uint8_t *ret; if (read_only) { ret = allocate_bump(read_section, read_bump_ptr, size, alignment); } else { - ret = - allocate_bump(readwrite_section, readwrite_bump_ptr, size, alignment); + ret = allocate_bump(readwrite_section, readwrite_bump_ptr, size, alignment); } if (section_name.equals(llvm::StringRef("__llvm_stackmaps")) || section_name.equals(llvm::StringRef(".llvm_stackmaps"))) { @@ -89,11 +85,12 @@ uint8_t *MemoryManager::allocateDataSection(uintptr_t size, unsigned alignment, return ret; } -void MemoryManager::reserveAllocationSpace(uintptr_t code_size, uint32_t code_align, - uintptr_t read_data_size, - uint32_t read_data_align, - uintptr_t read_write_data_size, - uint32_t read_write_data_align) { +void MemoryManager::reserveAllocationSpace(uintptr_t code_size, + uint32_t code_align, + uintptr_t read_data_size, + uint32_t read_data_align, + uintptr_t read_write_data_size, + uint32_t read_write_data_align) { auto aligner = [](uintptr_t ptr, size_t align) { if (ptr == 0) { return align; @@ -104,7 +101,7 @@ void MemoryManager::reserveAllocationSpace(uintptr_t code_size, uint32_t code_al size_t code_size_out = 0; auto code_result = callbacks.alloc_memory(aligner(code_size, 4096), PROTECT_READ_WRITE, - &code_ptr_out, &code_size_out); + &code_ptr_out, &code_size_out); assert(code_result == RESULT_OK); code_section = Section{code_ptr_out, code_size_out}; code_bump_ptr = (uintptr_t)code_ptr_out; @@ -113,9 +110,9 @@ void MemoryManager::reserveAllocationSpace(uintptr_t code_size, uint32_t code_al uint8_t *read_ptr_out = nullptr; size_t read_size_out = 0; - auto read_result = callbacks.alloc_memory(aligner(read_data_size, 4096), - PROTECT_READ_WRITE, &read_ptr_out, - &read_size_out); + auto read_result = + callbacks.alloc_memory(aligner(read_data_size, 4096), PROTECT_READ_WRITE, + &read_ptr_out, &read_size_out); assert(read_result == RESULT_OK); read_section = Section{read_ptr_out, read_size_out}; read_bump_ptr = (uintptr_t)read_ptr_out; @@ -133,7 +130,7 @@ void MemoryManager::reserveAllocationSpace(uintptr_t code_size, uint32_t code_al bool MemoryManager::needsToReserveAllocationSpace() { return true; } void MemoryManager::registerEHFrames(uint8_t *addr, uint64_t LoadAddr, - size_t size) { + size_t size) { // 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 @@ -157,7 +154,7 @@ void MemoryManager::deregisterEHFrames() { bool MemoryManager::finalizeMemory(std::string *ErrMsg) { auto code_result = callbacks.protect_memory(code_section.base, code_section.size, - mem_protect_t::PROTECT_READ_EXECUTE); + mem_protect_t::PROTECT_READ_EXECUTE); if (code_result != RESULT_OK) { return false; } @@ -174,10 +171,10 @@ bool MemoryManager::finalizeMemory(std::string *ErrMsg) { } void MemoryManager::notifyObjectLoaded(llvm::RuntimeDyld &RTDyld, - const llvm::object::ObjectFile &Obj) {} + const llvm::object::ObjectFile &Obj) {} -uint8_t *MemoryManager::allocate_bump(Section §ion, uintptr_t &bump_ptr, size_t size, - size_t align) { +uint8_t *MemoryManager::allocate_bump(Section §ion, uintptr_t &bump_ptr, + size_t size, size_t align) { auto aligner = [](uintptr_t &ptr, size_t align) { ptr = (ptr + align - 1) & ~(align - 1); }; diff --git a/lib/llvm-backend/cpp/object_loader.hh b/lib/llvm-backend/cpp/object_loader.hh index 319eed23266..9bcecbe2549 100644 --- a/lib/llvm-backend/cpp/object_loader.hh +++ b/lib/llvm-backend/cpp/object_loader.hh @@ -3,10 +3,10 @@ #include #include #include +#include #include -#include #include -#include +#include #include @@ -81,7 +81,7 @@ public: virtual void deregisterEHFrames() override; virtual bool finalizeMemory(std::string *ErrMsg = nullptr) override; virtual void notifyObjectLoaded(llvm::RuntimeDyld &RTDyld, - const llvm::object::ObjectFile &Obj) override; + const llvm::object::ObjectFile &Obj) override; private: struct Section { @@ -106,12 +106,12 @@ private: size_t stack_map_size = 0; }; -struct WasmException: std::exception { +struct WasmException : std::exception { public: virtual std::string description() const noexcept = 0; }; -void catch_unwind(std::function&& f); +void catch_unwind(std::function &&f); [[noreturn]] void unsafe_unwind(std::exception *exception); struct UncatchableException : WasmException { @@ -239,7 +239,9 @@ result_t module_load(const uint8_t *mem_ptr, size_t mem_size, return RESULT_OK; } -[[noreturn]] void throw_trap(WasmTrap::Type ty) { unsafe_unwind(new WasmTrap(ty)); } +[[noreturn]] void throw_trap(WasmTrap::Type ty) { + unsafe_unwind(new WasmTrap(ty)); +} void module_delete(WasmModule *module) { delete module; } @@ -260,7 +262,7 @@ bool invoke_trampoline(trampoline_t trampoline, void *ctx, void *func, box_any_t *user_error, void *invoke_env) noexcept { try { catch_unwind([trampoline, ctx, func, params, results]() { - trampoline(ctx, func, params, results); + trampoline(ctx, func, params, results); }); return true; } catch (const WasmTrap &e) { diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index 901730ae6f3..cdee5c60d44 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -331,7 +331,7 @@ impl LLVMBackend { local_func_id_to_offset, }, LLVMCache { buffer }, - ) + ); } } diff --git a/lib/llvm-backend/src/platform/unix.rs b/lib/llvm-backend/src/platform/unix.rs index b06746d9e00..9e77c57d6bf 100644 --- a/lib/llvm-backend/src/platform/unix.rs +++ b/lib/llvm-backend/src/platform/unix.rs @@ -4,7 +4,9 @@ use libc::{ 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, SIGILL}; +use nix::sys::signal::{ + sigaction, SaFlags, SigAction, SigHandler, SigSet, SIGBUS, SIGILL, SIGSEGV, +}; use std::ptr; /// `__register_frame` and `__deregister_frame` on macos take a single fde as an diff --git a/lib/llvm-backend/src/stackmap.rs b/lib/llvm-backend/src/stackmap.rs index f409d719ef2..27a16aafad6 100644 --- a/lib/llvm-backend/src/stackmap.rs +++ b/lib/llvm-backend/src/stackmap.rs @@ -232,10 +232,8 @@ impl StackmapEntry { if loc.offset_or_small_constant >= 0 { assert!(loc.offset_or_small_constant >= 16); // (saved_rbp, return_address) assert!(loc.offset_or_small_constant % 8 == 0); - prev_frame_diff.insert( - (loc.offset_or_small_constant as usize - 16) / 8, - Some(mv), - ); + prev_frame_diff + .insert((loc.offset_or_small_constant as usize - 16) / 8, Some(mv)); } else { let stack_offset = ((-loc.offset_or_small_constant) / 4) as usize; assert!( diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 39cd6b89751..b6bbb95f50d 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -726,11 +726,8 @@ pub mod x64 { assert_eq!(vmctx.internal.memory_bound, memory.len()); } - std::slice::from_raw_parts_mut( - vmctx.internal.memory_base, - vmctx.internal.memory_bound, - ) - .copy_from_slice(memory); + std::slice::from_raw_parts_mut(vmctx.internal.memory_base, vmctx.internal.memory_bound) + .copy_from_slice(memory); } let globals_len = (*vmctx.module).info.globals.len(); diff --git a/lib/runtime-core/src/tiering.rs b/lib/runtime-core/src/tiering.rs index 5980ac14606..21a9ea2d377 100644 --- a/lib/runtime-core/src/tiering.rs +++ b/lib/runtime-core/src/tiering.rs @@ -210,8 +210,7 @@ pub unsafe fn run_tiering ShellExitOperation>( if let Err(e) = ret { if let Ok(new_image) = e.downcast::() { // Tier switch event - if !was_sigint_triggered_fault() && opt_state.outcome.lock().unwrap().is_some() - { + if !was_sigint_triggered_fault() && opt_state.outcome.lock().unwrap().is_some() { resume_image = Some(*new_image); continue; } diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index aedb3ecc359..fb213c277b4 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -587,32 +587,34 @@ fn execute_wasm(options: &Run) -> Result<(), String> { 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, - )? }; + 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"))] From b0beb28ea7c49d9a8593e57f4c2d638ad9653072 Mon Sep 17 00:00:00 2001 From: losfair Date: Wed, 21 Aug 2019 15:32:20 -0700 Subject: [PATCH 45/90] Fix unused import on Windows. --- lib/llvm-backend/src/backend.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index cdee5c60d44..2a521d153e1 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -1,4 +1,4 @@ -use super::stackmap::{self, StackmapRegistry, StkMapRecord, StkSizeRecord}; +use super::stackmap::StackmapRegistry; use crate::intrinsics::Intrinsics; use crate::structs::{Callbacks, LLVMModule, LLVMResult, MemProtect}; use inkwell::{ @@ -228,6 +228,7 @@ impl LLVMBackend { #[cfg(all(any(target_os = "linux", target_os = "macos"), target_arch = "x86_64"))] { + use super::stackmap::{self, StkMapRecord, StkSizeRecord}; let raw_stackmap = unsafe { std::slice::from_raw_parts( llvm_backend_get_stack_map_ptr(module), From 7491b360ac48d0d9b82d1f9d48c453c84c1d344a Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 22 Aug 2019 11:57:58 -0700 Subject: [PATCH 46/90] Fix CodeMemory::new(0) --- lib/runtime-core/src/loader.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/runtime-core/src/loader.rs b/lib/runtime-core/src/loader.rs index 935d201a460..4f843a54da8 100644 --- a/lib/runtime-core/src/loader.rs +++ b/lib/runtime-core/src/loader.rs @@ -137,13 +137,20 @@ impl CodeMemory { #[cfg(unix)] impl CodeMemory { pub fn new(size: usize) -> CodeMemory { + if size == 0 { + return CodeMemory { + ptr: std::ptr::null_mut(), + size: 0, + }; + } + fn round_up_to_page_size(size: usize) -> usize { (size + (4096 - 1)) & !(4096 - 1) } let size = round_up_to_page_size(size); let ptr = unsafe { mmap( - ::std::ptr::null_mut(), + std::ptr::null_mut(), size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, From 115da5f1304ac2e056d5556bf7f43b2196747f11 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 22 Aug 2019 13:07:51 -0700 Subject: [PATCH 47/90] Try to fix missing git submodule --- cranelift | 1 - 1 file changed, 1 deletion(-) delete mode 160000 cranelift diff --git a/cranelift b/cranelift deleted file mode 160000 index cb62a1ead2c..00000000000 --- a/cranelift +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cb62a1ead2c5346ccb0f1224ecae5939ac064f87 From eef38429fcb92c2428a6b6e26ef6a3a59068527f Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 22 Aug 2019 13:14:05 -0700 Subject: [PATCH 48/90] Fix unused imports on Windows. --- lib/llvm-backend/src/backend.rs | 3 ++- lib/llvm-backend/src/stackmap.rs | 30 ++---------------------------- 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index 2a521d153e1..a32a8468b93 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -10,7 +10,6 @@ use inkwell::{ use libc::c_char; use std::{ any::Any, - collections::BTreeMap, ffi::{c_void, CString}, fs::File, io::Write, @@ -229,6 +228,8 @@ impl LLVMBackend { #[cfg(all(any(target_os = "linux", target_os = "macos"), target_arch = "x86_64"))] { use super::stackmap::{self, StkMapRecord, StkSizeRecord}; + use std::collections::BTreeMap; + let raw_stackmap = unsafe { std::slice::from_raw_parts( llvm_backend_get_stack_map_ptr(module), diff --git a/lib/llvm-backend/src/stackmap.rs b/lib/llvm-backend/src/stackmap.rs index 27a16aafad6..96fd40c780f 100644 --- a/lib/llvm-backend/src/stackmap.rs +++ b/lib/llvm-backend/src/stackmap.rs @@ -1,7 +1,6 @@ // https://llvm.org/docs/StackMaps.html#stackmap-section use byteorder::{LittleEndian, ReadBytesExt}; -use std::collections::{BTreeMap, HashMap}; use std::io::{self, Cursor}; use wasmer_runtime_core::vm::Ctx; use wasmer_runtime_core::{ @@ -54,33 +53,6 @@ pub enum StackmapEntryKind { Trappable, } -/* -pub struct FunctionStateMap { - pub initial: MachineState, - pub local_function_id: usize, - pub locals: Vec, - pub shadow_size: usize, // for single-pass backend, 32 bytes on x86-64 - pub diffs: Vec, - pub wasm_function_header_target_offset: Option, - pub wasm_offset_to_target_offset: BTreeMap, - pub loop_offsets: BTreeMap, /* suspend_offset -> info */ - pub call_offsets: BTreeMap, /* suspend_offset -> info */ - pub trappable_offsets: BTreeMap, /* suspend_offset -> info */ -} -pub struct MachineStateDiff { - pub last: Option, - pub stack_push: Vec, - pub stack_pop: usize, - pub reg_diff: Vec<(RegisterIndex, MachineValue)>, - - pub wasm_stack_push: Vec, - pub wasm_stack_pop: usize, - pub wasm_stack_private_depth: usize, // absolute value; not a diff. - - pub wasm_inst_offset: usize, // absolute value; not a diff. -} -*/ - impl StackmapEntry { #[cfg(all(any(target_os = "linux", target_os = "macos"), target_arch = "x86_64"))] pub fn populate_msm( @@ -93,11 +65,13 @@ impl StackmapEntry { end: Option<(&StackmapEntry, &StkMapRecord)>, msm: &mut wasmer_runtime_core::state::ModuleStateMap, ) { + use std::collections::{BTreeMap, HashMap}; use wasmer_runtime_core::state::{ x64::{new_machine_state, X64Register, GPR}, FunctionStateMap, MachineStateDiff, MachineValue, OffsetInfo, RegisterIndex, SuspendOffset, WasmAbstractValue, }; + let func_base_addr = (size_record.function_address as usize) .checked_sub(code_addr) .unwrap(); From d868445d09c38d13dbfa08e401133363a98d12a2 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 22 Aug 2019 13:19:46 -0700 Subject: [PATCH 49/90] Fix unused import 'vm' on Windows --- lib/llvm-backend/src/stackmap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/llvm-backend/src/stackmap.rs b/lib/llvm-backend/src/stackmap.rs index 96fd40c780f..a56c3c6a38d 100644 --- a/lib/llvm-backend/src/stackmap.rs +++ b/lib/llvm-backend/src/stackmap.rs @@ -7,7 +7,6 @@ use wasmer_runtime_core::{ module::ModuleInfo, structures::TypedIndex, types::{GlobalIndex, LocalOrImport, TableIndex}, - vm, }; #[derive(Default, Debug, Clone)] @@ -71,6 +70,7 @@ impl StackmapEntry { FunctionStateMap, MachineStateDiff, MachineValue, OffsetInfo, RegisterIndex, SuspendOffset, WasmAbstractValue, }; + use wasmer_runtime_core::vm; let func_base_addr = (size_record.function_address as usize) .checked_sub(code_addr) From e89ab43b988e5ac6c0db905b8185a072596de529 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 22 Aug 2019 13:25:52 -0700 Subject: [PATCH 50/90] Fix unused 'stackmaps' and 'module_info' on Windows --- lib/llvm-backend/src/backend.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index a32a8468b93..a0fb80c0352 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -170,8 +170,8 @@ impl LLVMBackend { pub fn new( module: Module, _intrinsics: Intrinsics, - stackmaps: &StackmapRegistry, - module_info: &ModuleInfo, + _stackmaps: &StackmapRegistry, + _module_info: &ModuleInfo, ) -> (Self, LLVMCache) { Target::initialize_x86(&InitializationConfig { asm_parser: true, @@ -230,6 +230,9 @@ impl LLVMBackend { use super::stackmap::{self, StkMapRecord, StkSizeRecord}; use std::collections::BTreeMap; + let stackmaps = _stackmaps; + let module_info = _module_info; + let raw_stackmap = unsafe { std::slice::from_raw_parts( llvm_backend_get_stack_map_ptr(module), From 6534c28aed6a61daf5b6be0046e3d3156aefefc4 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 22 Aug 2019 13:30:50 -0700 Subject: [PATCH 51/90] Allow dead code in llvm-backend. --- lib/llvm-backend/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/llvm-backend/src/lib.rs b/lib/llvm-backend/src/lib.rs index c160ef70e3b..015aacbdcba 100644 --- a/lib/llvm-backend/src/lib.rs +++ b/lib/llvm-backend/src/lib.rs @@ -1,5 +1,4 @@ #![deny( - dead_code, nonstandard_style, unused_imports, unused_mut, From d7c5bb904e07f6d7b6d930c54b2e27fae21cf2e8 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 22 Aug 2019 13:32:35 -0700 Subject: [PATCH 52/90] Only disallow dead code in llvm-backend for non-Windows environments. --- lib/llvm-backend/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/llvm-backend/src/lib.rs b/lib/llvm-backend/src/lib.rs index 015aacbdcba..480be9711c6 100644 --- a/lib/llvm-backend/src/lib.rs +++ b/lib/llvm-backend/src/lib.rs @@ -6,6 +6,7 @@ unused_unsafe, unreachable_patterns )] +#![cfg_attr(not(target_os = "windows"), deny(dead_code))] #![cfg_attr(nightly, feature(unwind_attributes))] mod backend; From f503764780792670f2c595b88683590a934449bb Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 22 Aug 2019 17:22:33 -0700 Subject: [PATCH 53/90] Restore previous unwind_state. --- lib/llvm-backend/cpp/object_loader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/llvm-backend/cpp/object_loader.cpp b/lib/llvm-backend/cpp/object_loader.cpp index 1e842b97e5a..666caa78f3b 100644 --- a/lib/llvm-backend/cpp/object_loader.cpp +++ b/lib/llvm-backend/cpp/object_loader.cpp @@ -44,6 +44,8 @@ void catch_unwind(std::function &&f) { unwind_state = ¤t; unwinding_setjmp(current.stack, unwind_payload, (void *)¤t); + + unwind_state = current.prev; if (current.exception) { throw *current.exception; } From bdcd73cd63fc5ec5b61fad6133f93b761073eddc Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 22 Aug 2019 17:45:52 -0700 Subject: [PATCH 54/90] Unblock signals in LLVM trap handler. --- lib/llvm-backend/src/platform/unix.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/llvm-backend/src/platform/unix.rs b/lib/llvm-backend/src/platform/unix.rs index 9e77c57d6bf..88ceb685438 100644 --- a/lib/llvm-backend/src/platform/unix.rs +++ b/lib/llvm-backend/src/platform/unix.rs @@ -69,6 +69,9 @@ extern "C" fn signal_trap_handler( _ucontext: *mut c_void, ) { unsafe { + if SigSet::all().thread_unblock().is_err() { + std::process::abort(); + } // Apparently, we can unwind from arbitary instructions, as long // as we don't need to catch the exception inside the function that // was interrupted. From dcb16a2ae9bc65508bd8d33867c4c26e41a0860a Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 22 Aug 2019 17:57:22 -0700 Subject: [PATCH 55/90] Disable `test_indirect_many` as a mitigation for issue #717 . --- lib/emscripten-tests/emtests/ignores.txt | 1 + lib/emscripten-tests/tests/emtests/test_indirectbr_many.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/emscripten-tests/emtests/ignores.txt b/lib/emscripten-tests/emtests/ignores.txt index 16ff1a2a7f6..af8f21b0037 100644 --- a/lib/emscripten-tests/emtests/ignores.txt +++ b/lib/emscripten-tests/emtests/ignores.txt @@ -29,6 +29,7 @@ test_i16_emcc_intrinsic test_i64 test_i64_7z test_i64_varargs +test_indirectbr_many test_llvm_intrinsics test_longjmp_exc test_lower_intrinsics diff --git a/lib/emscripten-tests/tests/emtests/test_indirectbr_many.rs b/lib/emscripten-tests/tests/emtests/test_indirectbr_many.rs index fba25e6b20e..a96fe213816 100644 --- a/lib/emscripten-tests/tests/emtests/test_indirectbr_many.rs +++ b/lib/emscripten-tests/tests/emtests/test_indirectbr_many.rs @@ -1,4 +1,5 @@ #[test] +#[ignore] fn test_test_indirectbr_many() { assert_emscripten_output!( "../../emtests/test_indirectbr_many.wasm", From 613e4de9fc626ecf99b433a0605ac919bf1d3e67 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 22 Aug 2019 18:57:26 -0700 Subject: [PATCH 56/90] Fix LLVM object loader exceptions. --- lib/llvm-backend/build.rs | 1 + lib/llvm-backend/cpp/object_loader.cpp | 6 +- lib/llvm-backend/cpp/object_loader.hh | 92 ++++++++++++++++---------- 3 files changed, 61 insertions(+), 38 deletions(-) diff --git a/lib/llvm-backend/build.rs b/lib/llvm-backend/build.rs index 8624c815271..f7198b0812f 100644 --- a/lib/llvm-backend/build.rs +++ b/lib/llvm-backend/build.rs @@ -253,6 +253,7 @@ fn get_llvm_cxxflags() -> String { .split(&[' ', '\n'][..]) .filter(|word| !word.starts_with("-W")) .filter(|word| word != &"-fno-exceptions") + .filter(|word| word != &"-fno-rtti") .collect::>() .join(" ") } diff --git a/lib/llvm-backend/cpp/object_loader.cpp b/lib/llvm-backend/cpp/object_loader.cpp index 666caa78f3b..c4fc6d93628 100644 --- a/lib/llvm-backend/cpp/object_loader.cpp +++ b/lib/llvm-backend/cpp/object_loader.cpp @@ -27,7 +27,7 @@ struct UnwindPoint { UnwindPoint *prev; jmp_buf stack; std::function *f; - std::unique_ptr exception; + std::unique_ptr exception; }; static thread_local UnwindPoint *unwind_state = nullptr; @@ -47,11 +47,11 @@ void catch_unwind(std::function &&f) { unwind_state = current.prev; if (current.exception) { - throw *current.exception; + throw std::move(current.exception); } } -void unsafe_unwind(std::exception *exception) { +void unsafe_unwind(WasmException *exception) { UnwindPoint *state = unwind_state; if (state) { state->exception.reset(exception); diff --git a/lib/llvm-backend/cpp/object_loader.hh b/lib/llvm-backend/cpp/object_loader.hh index 9bcecbe2549..bc9b9ab6717 100644 --- a/lib/llvm-backend/cpp/object_loader.hh +++ b/lib/llvm-backend/cpp/object_loader.hh @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -52,6 +53,17 @@ typedef struct { size_t data, vtable; } box_any_t; +enum WasmTrapType { + Unreachable = 0, + IncorrectCallIndirectSignature = 1, + MemoryOutOfBounds = 2, + CallIndirectOOB = 3, + IllegalArithmetic = 4, + Unknown, +}; + +extern "C" void callback_trampoline(void *, void *); + struct MemoryManager : llvm::RuntimeDyld::MemoryManager { public: MemoryManager(callbacks_t callbacks) : callbacks(callbacks) {} @@ -106,13 +118,26 @@ private: size_t stack_map_size = 0; }; +struct WasmErrorSink { + WasmTrapType *trap_out; + box_any_t *user_error; +}; + struct WasmException : std::exception { public: - virtual std::string description() const noexcept = 0; + virtual std::string description() const noexcept { return "unknown"; } + + virtual const char *what() const noexcept override { + return "wasm exception"; + } + + virtual void write_error(WasmErrorSink &out) const noexcept { + *out.trap_out = WasmTrapType::Unknown; + } }; void catch_unwind(std::function &&f); -[[noreturn]] void unsafe_unwind(std::exception *exception); +[[noreturn]] void unsafe_unwind(WasmException *exception); struct UncatchableException : WasmException { public: @@ -131,6 +156,10 @@ public: // The parts of a `Box`. box_any_t error_data; + + virtual void write_error(WasmErrorSink &out) const noexcept override { + *out.user_error = error_data; + } }; struct BreakpointException : UncatchableException { @@ -142,6 +171,11 @@ public: } uintptr_t callback; + + virtual void write_error(WasmErrorSink &out) const noexcept override { + puts("CB TRAMPOLINE"); + callback_trampoline(out.user_error, (void *)callback); + } }; struct WasmModule { @@ -165,16 +199,7 @@ private: struct WasmTrap : UncatchableException { public: - enum Type { - Unreachable = 0, - IncorrectCallIndirectSignature = 1, - MemoryOutOfBounds = 2, - CallIndirectOOB = 3, - IllegalArithmetic = 4, - Unknown, - }; - - WasmTrap(Type type) : type(type) {} + WasmTrap(WasmTrapType type) : type(type) {} virtual std::string description() const noexcept override { std::ostringstream ss; @@ -183,27 +208,31 @@ public: return ss.str(); } - Type type; + WasmTrapType type; + + virtual void write_error(WasmErrorSink &out) const noexcept override { + *out.trap_out = type; + } private: - friend std::ostream &operator<<(std::ostream &out, const Type &ty) { + friend std::ostream &operator<<(std::ostream &out, const WasmTrapType &ty) { switch (ty) { - case Type::Unreachable: + case WasmTrapType::Unreachable: out << "unreachable"; break; - case Type::IncorrectCallIndirectSignature: + case WasmTrapType::IncorrectCallIndirectSignature: out << "incorrect call_indirect signature"; break; - case Type::MemoryOutOfBounds: + case WasmTrapType::MemoryOutOfBounds: out << "memory access out-of-bounds"; break; - case Type::CallIndirectOOB: + case WasmTrapType::CallIndirectOOB: out << "call_indirect out-of-bounds"; break; - case Type::IllegalArithmetic: + case WasmTrapType::IllegalArithmetic: out << "illegal arithmetic operation"; break; - case Type::Unknown: + case WasmTrapType::Unknown: default: out << "unknown"; break; @@ -226,7 +255,6 @@ public: }; extern "C" { -void callback_trampoline(void *, void *); result_t module_load(const uint8_t *mem_ptr, size_t mem_size, callbacks_t callbacks, WasmModule **module_out) { @@ -239,7 +267,7 @@ result_t module_load(const uint8_t *mem_ptr, size_t mem_size, return RESULT_OK; } -[[noreturn]] void throw_trap(WasmTrap::Type ty) { +[[noreturn]] void throw_trap(WasmTrapType ty) { unsafe_unwind(new WasmTrap(ty)); } @@ -258,27 +286,21 @@ void module_delete(WasmModule *module) { delete module; } } bool invoke_trampoline(trampoline_t trampoline, void *ctx, void *func, - void *params, void *results, WasmTrap::Type *trap_out, + void *params, void *results, WasmTrapType *trap_out, box_any_t *user_error, void *invoke_env) noexcept { try { catch_unwind([trampoline, ctx, func, params, results]() { trampoline(ctx, func, params, results); }); return true; - } catch (const WasmTrap &e) { - *trap_out = e.type; - return false; - } catch (const UserException &e) { - *user_error = e.error_data; - return false; - } catch (const BreakpointException &e) { - callback_trampoline(user_error, (void *)e.callback); - return false; - } catch (const WasmException &e) { - *trap_out = WasmTrap::Type::Unknown; + } catch (std::unique_ptr &e) { + WasmErrorSink sink; + sink.trap_out = trap_out; + sink.user_error = user_error; + e->write_error(sink); return false; } catch (...) { - *trap_out = WasmTrap::Type::Unknown; + *trap_out = WasmTrapType::Unknown; return false; } } From 212e2be1664923752ce132b2ce03dd6e89be9ff4 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 22 Aug 2019 22:58:08 -0700 Subject: [PATCH 57/90] Remove `-fno-rtti` --- lib/llvm-backend/build.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/llvm-backend/build.rs b/lib/llvm-backend/build.rs index f7198b0812f..8624c815271 100644 --- a/lib/llvm-backend/build.rs +++ b/lib/llvm-backend/build.rs @@ -253,7 +253,6 @@ fn get_llvm_cxxflags() -> String { .split(&[' ', '\n'][..]) .filter(|word| !word.starts_with("-W")) .filter(|word| word != &"-fno-exceptions") - .filter(|word| word != &"-fno-rtti") .collect::>() .join(" ") } From d9ce2591f6d7aa58ef282f0975d13b94fc6aaecc Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 1 Sep 2019 02:28:59 -0700 Subject: [PATCH 58/90] Improved Readme --- README.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index a023b1a2cea..e4fa07e059d 100644 --- a/README.md +++ b/README.md @@ -35,19 +35,19 @@ curl https://get.wasmer.io -sSfL | sh Wasmer runtime can be used as a library embedded in different languages, so you can use WebAssembly anywhere: -|   | Language | Author(s) | Maintenance | Release | -|-|-|-|-|-| -| ![Rust logo](./docs/assets/languages/rust.svg) | [**Rust**](https://github.com/wasmerio/wasmer-rust-example) | Wasmer | actively developed | ![last release](https://img.shields.io/crates/v/wasmer-runtime?style=flat-square) ![number of Github stars](https://img.shields.io/github/stars/wasmerio/wasmer?style=flat-square) | -| ![C logo](./docs/assets/languages/c.svg) | [**C/C++**](https://github.com/wasmerio/wasmer-c-api) | Wasmer | actively developed | ![last release](https://img.shields.io/github/v/release/wasmerio/wasmer?style=flat-square) ![number of Github stars](https://img.shields.io/github/stars/wasmerio/wasmer?style=flat-square) | -| ![Python logo](./docs/assets/languages/python.svg) | [**Python**](https://github.com/wasmerio/python-ext-wasm) | Wasmer | actively developed | ![last release](https://img.shields.io/pypi/v/wasmer?style=flat-square) ![number of Github stars](https://img.shields.io/github/stars/wasmerio/python-ext-wasm?style=flat-square) | -| ![Go logo](./docs/assets/languages/go.svg) | [**Go**](https://github.com/wasmerio/go-ext-wasm) | Wasmer | actively developed | ![last release](https://img.shields.io/github/v/release/wasmerio/go-ext-wasm?style=flat-square) ![number of Github stars](https://img.shields.io/github/stars/wasmerio/go-ext-wasm?style=flat-square) | -| ![PHP logo](./docs/assets/languages/php.svg) | [**PHP**](https://github.com/wasmerio/php-ext-wasm) | Wasmer | actively developed | ![last release](https://img.shields.io/github/v/release/wasmerio/php-ext-wasm?style=flat-square) ![number of Github stars](https://img.shields.io/github/stars/wasmerio/php-ext-wasm?style=flat-square) | -| ![Ruby logo](./docs/assets/languages/ruby.svg) | [**Ruby**](https://github.com/wasmerio/ruby-ext-wasm) | Wasmer | actively developed | ![last release](https://img.shields.io/gem/v/wasmer?style=flat-square) ![number of Github stars](https://img.shields.io/github/stars/wasmerio/ruby-ext-wasm?style=flat-square) | -| ![Postgres logo](./docs/assets/languages/postgres.svg) | [**Postgres**](https://github.com/wasmerio/postgres-ext-wasm) | Wasmer | actively developed | ![last release](https://img.shields.io/github/v/release/wasmerio/postgres-ext-wasm?style=flat-square) ![number of Github stars](https://img.shields.io/github/stars/wasmerio/postgres-ext-wasm?style=flat-square) | -| ![C# logo](./docs/assets/languages/csharp.svg) | [**C#/.Net**](https://github.com/migueldeicaza/WasmerSharp) | [Miguel de Icaza](https://github.com/migueldeicaza) | actively developed | ![last release](https://img.shields.io/nuget/v/WasmerSharp?style=flat-square) ![number of Github stars](https://img.shields.io/github/stars/migueldeicaza/WasmerSharp?style=flat-square) | -| ![R logo](./docs/assets/languages/r.svg) | [**R**](https://github.com/dirkschumacher/wasmr) | [Dirk Schumacher](https://github.com/dirkschumacher) | actively developed | ![number of Github stars](https://img.shields.io/github/stars/dirkschumacher/wasmr?style=flat-square) | -| ![Swift logo](./docs/assets/languages/swift.svg) | [**Swift**](https://github.com/markmals/swift-ext-wasm) | [Mark Malström](https://github.com/markmals/) | passively maintened | ![number of Github stars](https://img.shields.io/github/stars/markmals/swift-ext-wasm?style=flat-square) | -| ❓ | [your language is missing?](https://github.com/wasmerio/wasmer/issues/new?assignees=&labels=%F0%9F%8E%89+enhancement&template=---feature-request.md&title=) | | | +|   | Language | Author(s) | Maintenance | Release | Stars | +|-|-|-|-|-|-| +| ![Rust logo](./docs/assets/languages/rust.svg) | [**Rust**](https://github.com/wasmerio/wasmer-rust-example) | Wasmer | actively developed | ![last release](https://img.shields.io/crates/v/wasmer-runtime?style=flat-square) | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/wasmer?style=flat-square) | +| ![C logo](./docs/assets/languages/c.svg) | [**C/C++**](https://github.com/wasmerio/wasmer-c-api) | Wasmer | actively developed | ![last release](https://img.shields.io/github/v/release/wasmerio/wasmer?style=flat-square) | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/wasmer?style=flat-square) | +| ![Python logo](./docs/assets/languages/python.svg) | [**Python**](https://github.com/wasmerio/python-ext-wasm) | Wasmer | actively developed | ![last release](https://img.shields.io/pypi/v/wasmer?style=flat-square) | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/python-ext-wasm?style=flat-square) | +| ![Go logo](./docs/assets/languages/go.svg) | [**Go**](https://github.com/wasmerio/go-ext-wasm) | Wasmer | actively developed | ![last release](https://img.shields.io/github/v/release/wasmerio/go-ext-wasm?style=flat-square) | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/go-ext-wasm?style=flat-square) | +| ![PHP logo](./docs/assets/languages/php.svg) | [**PHP**](https://github.com/wasmerio/php-ext-wasm) | Wasmer | actively developed | ![last release](https://img.shields.io/github/v/release/wasmerio/php-ext-wasm?style=flat-square) | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/php-ext-wasm?style=flat-square) | +| ![Ruby logo](./docs/assets/languages/ruby.svg) | [**Ruby**](https://github.com/wasmerio/ruby-ext-wasm) | Wasmer | actively developed | ![last release](https://img.shields.io/gem/v/wasmer?style=flat-square) | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/ruby-ext-wasm?style=flat-square) | +| ![Postgres logo](./docs/assets/languages/postgres.svg) | [**Postgres**](https://github.com/wasmerio/postgres-ext-wasm) | Wasmer | actively developed | ![last release](https://img.shields.io/github/v/release/wasmerio/postgres-ext-wasm?style=flat-square) | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/postgres-ext-wasm?style=flat-square) | +| ![C# logo](./docs/assets/languages/csharp.svg) | [**C#/.Net**](https://github.com/migueldeicaza/WasmerSharp) | [Miguel de Icaza](https://github.com/migueldeicaza) | actively developed | ![last release](https://img.shields.io/nuget/v/WasmerSharp?style=flat-square) | ![number of Github stars](https://img.shields.io/github/stars/migueldeicaza/WasmerSharp?style=flat-square) | +| ![R logo](./docs/assets/languages/r.svg) | [**R**](https://github.com/dirkschumacher/wasmr) | [Dirk Schumacher](https://github.com/dirkschumacher) | actively developed | | ![number of Github stars](https://img.shields.io/github/stars/dirkschumacher/wasmr?style=flat-square) | +| ![Swift logo](./docs/assets/languages/swift.svg) | [**Swift**](https://github.com/markmals/swift-ext-wasm) | [Mark Malström](https://github.com/markmals/) | passively maintened | | ![number of Github stars](https://img.shields.io/github/stars/markmals/swift-ext-wasm?style=flat-square) | +| ❓ | [your language is missing?](https://github.com/wasmerio/wasmer/issues/new?assignees=&labels=%F0%9F%8E%89+enhancement&template=---feature-request.md&title=) | | | | ### Usage @@ -177,7 +177,7 @@ nginx and Lua do not work on Windows - you can track the progress on [this issue ## Building -[![Rustc Version 1.36+](https://img.shields.io/badge/rustc-1.36+-red.svg)](https://blog.rust-lang.org/2019/07/04/Rust-1.36.0.html) +[![Rustc Version 1.36+](https://img.shields.io/badge/rustc-1.36+-red.svg?style=flat-square)](https://blog.rust-lang.org/2019/07/04/Rust-1.36.0.html) Wasmer is built with [Cargo](https://crates.io/), the Rust package manager. From 179b3a3f186655fac94aba19cbab762cb42b78a3 Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 1 Sep 2019 02:46:58 -0700 Subject: [PATCH 59/90] Use ubuntu for the check --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9ae585715a1..a85138e5fe4 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -55,7 +55,7 @@ jobs: - job: Check pool: - vmImage: "macos-10.14" + vmImage: "ubuntu-16.04" variables: rust_toolchain: nightly-2019-06-10 condition: in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying') From 45040650ddcf7c33872a8b37216925baa86ed3b4 Mon Sep 17 00:00:00 2001 From: losfair Date: Sun, 1 Sep 2019 18:17:31 +0800 Subject: [PATCH 60/90] Fix the missing Copy trait error --- lib/singlepass-backend/src/machine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/singlepass-backend/src/machine.rs b/lib/singlepass-backend/src/machine.rs index fdabfca9a60..b48115cedf0 100644 --- a/lib/singlepass-backend/src/machine.rs +++ b/lib/singlepass-backend/src/machine.rs @@ -494,7 +494,7 @@ mod test { let mut assembler = Assembler::new().unwrap(); let locs = machine.acquire_locations( &mut assembler, - &[(WpType::I32, MachineValue::Undefined); 10], + &(0..10).map(|_| (WpType::I32, MachineValue::Undefined)).collect::>(), false, ); From 9015b790911553339566b4b347b39067527fc8e8 Mon Sep 17 00:00:00 2001 From: losfair Date: Sun, 1 Sep 2019 18:17:47 +0800 Subject: [PATCH 61/90] Cargo fmt --- lib/singlepass-backend/src/machine.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/singlepass-backend/src/machine.rs b/lib/singlepass-backend/src/machine.rs index b48115cedf0..1535ef8530a 100644 --- a/lib/singlepass-backend/src/machine.rs +++ b/lib/singlepass-backend/src/machine.rs @@ -494,7 +494,9 @@ mod test { let mut assembler = Assembler::new().unwrap(); let locs = machine.acquire_locations( &mut assembler, - &(0..10).map(|_| (WpType::I32, MachineValue::Undefined)).collect::>(), + &(0..10) + .map(|_| (WpType::I32, MachineValue::Undefined)) + .collect::>(), false, ); From 659c504da4f932a5d475b8837a1ffcef73cf36ea Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 1 Sep 2019 08:51:36 -0700 Subject: [PATCH 62/90] Updated pipelines to not fail --- azure-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a85138e5fe4..1a5d8ed4210 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -116,6 +116,7 @@ jobs: condition: | and( succeeded(), + eq(variables['Build.SourceBranch'], 'refs/heads/master'), not(eq(variables['Agent.OS'], 'Windows_NT')) ) - bash: | From dc02d0e40128435439e27590843905b1fe1ee5e1 Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 1 Sep 2019 08:52:03 -0700 Subject: [PATCH 63/90] Comment LLVM SIMD spectests on Linux after OSR --- lib/spectests/tests/excludes.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index 5402157ede3..d78aa08096f 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -1,3 +1,4 @@ + # Comment lines begin with # are ignored, empty lines are ignored # Exclude lines follow the format: # ::: @@ -860,6 +861,11 @@ llvm:skip:traps.wast:*:windows llvm:skip:unreachable.wast:*:windows llvm:skip:unwind.wast:*:windows +# LLVM Linux after OSR +llvm:fail:simd.wast:355:linux # Module - caught panic Any +llvm:fail:simd_binaryen.wast:*:linux # Module - caught panic Any + + # Singlepass singlepass:skip:atomic.wast:* # Threads not implemented singlepass:skip:simd.wast:* # SIMD not implemented From bc990cc18a491bb96c651cd5b2c2767bbfd79c96 Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 1 Sep 2019 08:52:19 -0700 Subject: [PATCH 64/90] Updated Runtime C API comments --- lib/runtime-c-api/wasmer.h | 21 +++++++++++++++++++++ lib/runtime-c-api/wasmer.hh | 7 +++++++ 2 files changed, 28 insertions(+) diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 297428ee275..816dbfeac9e 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -6,6 +6,9 @@ #include #include +/** + * List of export/import kinds. + */ enum wasmer_import_export_kind { WASM_FUNCTION, WASM_GLOBAL, @@ -31,6 +34,9 @@ typedef struct { } wasmer_module_t; +/** + * Opaque pointer to `NamedExportDescriptor`. + */ typedef struct { } wasmer_export_descriptor_t; @@ -40,10 +46,16 @@ typedef struct { uint32_t bytes_len; } wasmer_byte_array; +/** + * Opaque pointer to `NamedExportDescriptors`. + */ typedef struct { } wasmer_export_descriptors_t; +/** + * Opaque pointer to `wasmer_export_t`. + */ typedef struct { } wasmer_export_func_t; @@ -60,6 +72,9 @@ typedef struct { wasmer_value value; } wasmer_value_t; +/** + * Opaque pointer to `NamedExport`. + */ typedef struct { } wasmer_export_t; @@ -68,6 +83,9 @@ typedef struct { } wasmer_memory_t; +/** + * Opaque pointer to `NamedExports`. + */ typedef struct { } wasmer_exports_t; @@ -101,6 +119,9 @@ typedef struct { } wasmer_table_t; +/** + * Union of import/export value. + */ typedef union { const wasmer_import_func_t *func; const wasmer_table_t *table; diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index cf7a1c7b321..afe82536466 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -6,6 +6,7 @@ #include #include +/// List of export/import kinds. enum class wasmer_import_export_kind : uint32_t { WASM_FUNCTION, WASM_GLOBAL, @@ -29,6 +30,7 @@ struct wasmer_module_t { }; +/// Opaque pointer to `NamedExportDescriptor`. struct wasmer_export_descriptor_t { }; @@ -38,10 +40,12 @@ struct wasmer_byte_array { uint32_t bytes_len; }; +/// Opaque pointer to `NamedExportDescriptors`. struct wasmer_export_descriptors_t { }; +/// Opaque pointer to `wasmer_export_t`. struct wasmer_export_func_t { }; @@ -58,6 +62,7 @@ struct wasmer_value_t { wasmer_value value; }; +/// Opaque pointer to `NamedExport`. struct wasmer_export_t { }; @@ -66,6 +71,7 @@ struct wasmer_memory_t { }; +/// Opaque pointer to `NamedExports`. struct wasmer_exports_t { }; @@ -99,6 +105,7 @@ struct wasmer_table_t { }; +/// Union of import/export value. union wasmer_import_export_value { const wasmer_import_func_t *func; const wasmer_table_t *table; From 416d8d13d142e1e56bc88754dcec77b38c35ed1b Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 1 Sep 2019 09:30:31 -0700 Subject: [PATCH 65/90] Fix tests exclusion --- lib/spectests/tests/excludes.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index d78aa08096f..41a9a67f11c 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -861,9 +861,9 @@ llvm:skip:traps.wast:*:windows llvm:skip:unreachable.wast:*:windows llvm:skip:unwind.wast:*:windows -# LLVM Linux after OSR -llvm:fail:simd.wast:355:linux # Module - caught panic Any -llvm:fail:simd_binaryen.wast:*:linux # Module - caught panic Any +# LLVM Linux after OSR - https://github.com/wasmerio/wasmer/pull/567 +llvm:fail:simd.wast:355:unix # Module - caught panic Any +llvm:fail:simd_binaryen.wast:*:unix # Module - caught panic Any # Singlepass From c7c7a5cee1a5bbf87dec98f4eae2e2edbef342bc Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 1 Sep 2019 09:42:07 -0700 Subject: [PATCH 66/90] Improved capi tests --- Makefile | 4 +++- azure-pipelines.yml | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index a65a0a9d4b5..1dbb03d81b2 100644 --- a/Makefile +++ b/Makefile @@ -96,9 +96,11 @@ llvm: spectests-llvm emtests-llvm wasitests-llvm capi: cargo build --release cargo build -p wasmer-runtime-c-api --release + +test-capi: capi cargo test -p wasmer-runtime-c-api --release -test-rest: capi +test-rest: cargo test --release --all --exclude wasmer-runtime-c-api --exclude wasmer-emscripten --exclude wasmer-spectests --exclude wasmer-wasi --exclude wasmer-middleware-common --exclude wasmer-middleware-common-tests --exclude wasmer-singlepass-backend --exclude wasmer-clif-backend --exclude wasmer-llvm-backend --exclude wasmer-wasi-tests --exclude wasmer-emscripten-tests circleci-clean: diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1a5d8ed4210..f3099f66df4 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -162,18 +162,21 @@ jobs: displayName: Create Artifacts Dir - bash: | make capi + make test-capi cp target/release/libwasmer_runtime_c_api.so ./artifacts displayName: Build c-api (Linux) condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) - bash: | make capi + make test-capi install_name_tool -id "@rpath/libwasmer_runtime_c_api.dylib" target/release/libwasmer_runtime_c_api.dylib cp target/release/libwasmer_runtime_c_api.dylib ./artifacts displayName: Build c-api (Darwin) condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin')) - bash: | - cargo build --release - cargo build -p wasmer-runtime-c-api --release + make capi + # Tests are failing on Windows, comment for now + # make test-capi cp target/release/wasmer_runtime_c_api.dll ./artifacts displayName: Build c-api (Windows) condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) From 0b3413da737088f32ff318eb402369af0d47e5c6 Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 1 Sep 2019 09:42:21 -0700 Subject: [PATCH 67/90] Improved Rust installation --- .azure/install-rust.yml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/.azure/install-rust.yml b/.azure/install-rust.yml index 4a7a340c01a..e2fe9b26cf2 100644 --- a/.azure/install-rust.yml +++ b/.azure/install-rust.yml @@ -15,24 +15,24 @@ steps: echo "##vso[task.prependpath]$HOME/.cargo/bin" fi displayName: "Install Rust (Linux, macOS)" - condition: not(eq(variables['Agent.OS'], 'Windows_NT')) + condition: ne(variables['Agent.OS'], 'Windows_NT') - - bash: | - set -ex - if [ -x "`command -v rustup`" ]; then - echo `command -v rustup` `rustup -V` installed - else - choco install rust -y - # curl -sSf -o rustup-init.exe https://win.rustup.rs - # ./rustup-init.exe -y --default-toolchain $RUST_TOOLCHAIN - # echo "##vso[task.prependpath]$USERPROFILE/.cargo/bin" - fi - displayName: "Install Rust (Windows)" - condition: eq(variables['Agent.OS'], 'Windows_NT') + # - bash: | + # set -ex + # if [ -x "`command -v rustup`" ]; then + # echo `command -v rustup` `rustup -V` installed + # else + # choco install rust -y + # # curl -sSf -o rustup-init.exe https://win.rustup.rs + # # ./rustup-init.exe -y --default-toolchain $RUST_TOOLCHAIN + # # echo "##vso[task.prependpath]$USERPROFILE/.cargo/bin" + # fi + # displayName: "Install Rust (Windows)" + # condition: eq(variables['Agent.OS'], 'Windows_NT') - bash: | set -ex - rustup update $RUST_TOOLCHAIN + rustup update --no-self-update $RUST_TOOLCHAIN rustup default $RUST_TOOLCHAIN rustc -Vv From 112b478f4c438eb49e635001aca5839fc18b58a5 Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 1 Sep 2019 10:20:37 -0700 Subject: [PATCH 68/90] Trying to fix cargo ssl issue --- .azure/install-rust.yml | 11 +++++++++-- azure-pipelines.yml | 26 +++++++++++++++----------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/.azure/install-rust.yml b/.azure/install-rust.yml index e2fe9b26cf2..bea5e7530f9 100644 --- a/.azure/install-rust.yml +++ b/.azure/install-rust.yml @@ -14,8 +14,15 @@ steps: curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $RUST_TOOLCHAIN echo "##vso[task.prependpath]$HOME/.cargo/bin" fi - displayName: "Install Rust (Linux, macOS)" - condition: ne(variables['Agent.OS'], 'Windows_NT') + displayName: "Install Rust (Linux)" + condition: eq(variables['Agent.OS'], 'Linux') + - bash: | + set -ex + brew install openssl + brew link openssl --force + brew install rust + displayName: "Install Rust (macOS)" + condition: eq(variables['Agent.OS'], 'Darwin') # - bash: | # set -ex diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f3099f66df4..d35b2960487 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -29,10 +29,14 @@ jobs: matrix: linux: imageName: "ubuntu-16.04" - rust_toolchain: nightly-2019-06-10 + rust_toolchain: nightly-2019-07-04 mac: imageName: "macos-10.14" - rust_toolchain: nightly-2019-06-10 + rust_toolchain: nightly-2019-07-04 + # By default schannel checks revocation of certificates unlike some other SSL + # backends, but we've historically had problems on CI where a revocation + # server goes down presumably. See #43333 for more info + CARGO_HTTP_CHECK_REVOKE: false windows: imageName: "vs2017-win2016" rust_toolchain: stable @@ -43,9 +47,9 @@ jobs: - checkout: self submodules: true - template: .azure/install-rust.yml + - template: .azure/install-llvm.yml - template: .azure/install-sccache.yml - template: .azure/install-cmake.yml - - template: .azure/install-llvm.yml - bash: make test displayName: Tests (*nix) condition: and(succeeded(), not(eq(variables['Agent.OS'], 'Windows_NT'))) @@ -57,15 +61,15 @@ jobs: pool: vmImage: "ubuntu-16.04" variables: - rust_toolchain: nightly-2019-06-10 + rust_toolchain: nightly-2019-07-04 condition: in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying') steps: - checkout: self submodules: true - template: .azure/install-rust.yml + - template: .azure/install-llvm.yml - template: .azure/install-sccache.yml - template: .azure/install-cmake.yml - - template: .azure/install-llvm.yml - bash: make check displayName: Check with Flags condition: and(succeeded(), not(eq(variables['Agent.OS'], 'Windows_NT'))) @@ -75,10 +79,10 @@ jobs: matrix: linux: imageName: "ubuntu-16.04" - rust_toolchain: nightly-2019-06-10 + rust_toolchain: nightly-2019-07-04 mac: imageName: "macos-10.14" - rust_toolchain: nightly-2019-06-10 + rust_toolchain: nightly-2019-07-04 MACOSX_DEPLOYMENT_TARGET: 10.10 windows: imageName: "vs2017-win2016" @@ -91,10 +95,10 @@ jobs: - checkout: self submodules: true - template: .azure/install-rust.yml + - template: .azure/install-llvm.yml - template: .azure/install-sccache.yml - template: .azure/install-cmake.yml - template: .azure/install-innosetup.yml - - template: .azure/install-llvm.yml - bash: | mkdir -p artifacts displayName: Create Artifacts Dir @@ -138,10 +142,10 @@ jobs: matrix: linux: imageName: "ubuntu-16.04" - rust_toolchain: nightly-2019-06-10 + rust_toolchain: nightly-2019-07-04 mac: imageName: "macos-10.14" - rust_toolchain: nightly-2019-06-10 + rust_toolchain: nightly-2019-07-04 MACOSX_DEPLOYMENT_TARGET: 10.10 windows: imageName: "vs2017-win2016" @@ -154,9 +158,9 @@ jobs: - checkout: self submodules: true - template: .azure/install-rust.yml + # - template: .azure/install-llvm.yml - template: .azure/install-sccache.yml - template: .azure/install-cmake.yml - # - template: .azure/install-llvm.yml - bash: | mkdir -p artifacts displayName: Create Artifacts Dir From 20c296ef2bda5c4ac7967c160a7c813574f4a47f Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 1 Sep 2019 10:21:46 -0700 Subject: [PATCH 69/90] Fixed excludes --- lib/spectests/tests/excludes.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index 41a9a67f11c..2f077f55981 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -862,8 +862,8 @@ llvm:skip:unreachable.wast:*:windows llvm:skip:unwind.wast:*:windows # LLVM Linux after OSR - https://github.com/wasmerio/wasmer/pull/567 -llvm:fail:simd.wast:355:unix # Module - caught panic Any -llvm:fail:simd_binaryen.wast:*:unix # Module - caught panic Any +llvm:skip:simd.wast:355:unix # Module - caught panic Any +llvm:skip:simd_binaryen.wast:*:unix # Module - caught panic Any # Singlepass From 259c47612289b54e49f964d9127ee645e5b8d805 Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 1 Sep 2019 10:28:49 -0700 Subject: [PATCH 70/90] Trying to fix Windows install --- .azure/install-llvm.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.azure/install-llvm.yml b/.azure/install-llvm.yml index 0a2a674b11a..cd23c5a708b 100644 --- a/.azure/install-llvm.yml +++ b/.azure/install-llvm.yml @@ -34,13 +34,14 @@ steps: if [ -x "`command -v llvm-config`" ]; then echo `command -v cmake` `llvm-config --version` installed else + mkdir C:\projects\deps + cd C:\projects\deps curl -OL https://github.com/wasmerio/windows-llvm-build/releases/download/v8.0.0/llvm-8.0.0-install.zip 7z x llvm-8.0.0-install.zip LLVM_PATH=`pwd`/llvm-8.0.0-install - LLVM_PATH_WIN=$SYSTEM_DEFAULTWORKINGDIRECTORY\\llvm-8.0.0-install + LLVM_PATH_WIN=C:\projects\deps\llvm-8.0.0-install echo "##vso[task.prependpath]$LLVM_PATH/bin" echo "##vso[task.setvariable variable=LLVM_SYS_80_PREFIX]$LLVM_PATH_WIN" - # chocolatey install cmake --installargs 'ADD_CMAKE_TO_PATH=System' fi displayName: "Install LLVM (Windows)" condition: eq(variables['Agent.OS'], 'Windows_NT') From cfb01e8c73bf0aba0cac10c7d66b1db5fad35b6f Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 1 Sep 2019 10:35:50 -0700 Subject: [PATCH 71/90] Trying to fix errors --- .azure/install-llvm.yml | 6 ++---- .azure/install-rust.yml | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.azure/install-llvm.yml b/.azure/install-llvm.yml index cd23c5a708b..75ea611d127 100644 --- a/.azure/install-llvm.yml +++ b/.azure/install-llvm.yml @@ -38,10 +38,8 @@ steps: cd C:\projects\deps curl -OL https://github.com/wasmerio/windows-llvm-build/releases/download/v8.0.0/llvm-8.0.0-install.zip 7z x llvm-8.0.0-install.zip - LLVM_PATH=`pwd`/llvm-8.0.0-install - LLVM_PATH_WIN=C:\projects\deps\llvm-8.0.0-install - echo "##vso[task.prependpath]$LLVM_PATH/bin" - echo "##vso[task.setvariable variable=LLVM_SYS_80_PREFIX]$LLVM_PATH_WIN" + echo "##vso[task.prependpath]/c/projects/deps/llvm-8.0.0-install/bin" + echo "##vso[task.setvariable variable=LLVM_SYS_80_PREFIX]C:\\projects\\deps\\llvm-8.0.0-install" fi displayName: "Install LLVM (Windows)" condition: eq(variables['Agent.OS'], 'Windows_NT') diff --git a/.azure/install-rust.yml b/.azure/install-rust.yml index bea5e7530f9..fc1ade42ca2 100644 --- a/.azure/install-rust.yml +++ b/.azure/install-rust.yml @@ -20,7 +20,7 @@ steps: set -ex brew install openssl brew link openssl --force - brew install rust + brew install rustup displayName: "Install Rust (macOS)" condition: eq(variables['Agent.OS'], 'Darwin') From 5b554900489fb2ccde0a155dc7279b3b2dd5fabd Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 1 Sep 2019 10:45:32 -0700 Subject: [PATCH 72/90] Fix Rust install --- .azure/install-rust.yml | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/.azure/install-rust.yml b/.azure/install-rust.yml index fc1ade42ca2..b26aca87e86 100644 --- a/.azure/install-rust.yml +++ b/.azure/install-rust.yml @@ -6,6 +6,15 @@ # Wasm-bindgen template: https://github.com/rustwasm/wasm-bindgen/blob/master/ci/azure-install-rust.yml steps: + - bash: | + set -ex + brew install openssl curl + brew link openssl --force + echo "##vso[task.prependpath]/usr/local/opt/openssl/bin" + echo "##vso[task.setvariable variable=LDFLAGS;]-L/usr/local/opt/openssl/lib" + echo "##vso[task.setvariable variable=CPPFLAGS;]-I/usr/local/opt/openssl/include" + displayName: "Fix Cargo SSL (macOS)" + condition: eq(variables['Agent.OS'], 'Darwin') - bash: | set -ex if [ -x "`command -v rustup`" ]; then @@ -14,15 +23,8 @@ steps: curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $RUST_TOOLCHAIN echo "##vso[task.prependpath]$HOME/.cargo/bin" fi - displayName: "Install Rust (Linux)" - condition: eq(variables['Agent.OS'], 'Linux') - - bash: | - set -ex - brew install openssl - brew link openssl --force - brew install rustup - displayName: "Install Rust (macOS)" - condition: eq(variables['Agent.OS'], 'Darwin') + displayName: "Install Rust (Linux, macOS)" + condition: ne(variables['Agent.OS'], 'Windows_NT') # - bash: | # set -ex From 4c2e5eddf7e83a39b81969b0f7cecadb33a79d94 Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 1 Sep 2019 10:51:16 -0700 Subject: [PATCH 73/90] Fix LLVM on Windows --- .azure/install-llvm.yml | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/.azure/install-llvm.yml b/.azure/install-llvm.yml index 75ea611d127..4971ab36679 100644 --- a/.azure/install-llvm.yml +++ b/.azure/install-llvm.yml @@ -29,19 +29,27 @@ steps: displayName: "Install LLVM (Linux)" condition: eq(variables['Agent.OS'], 'Linux') - - bash: | - set -ex - if [ -x "`command -v llvm-config`" ]; then - echo `command -v cmake` `llvm-config --version` installed - else - mkdir C:\projects\deps - cd C:\projects\deps - curl -OL https://github.com/wasmerio/windows-llvm-build/releases/download/v8.0.0/llvm-8.0.0-install.zip - 7z x llvm-8.0.0-install.zip - echo "##vso[task.prependpath]/c/projects/deps/llvm-8.0.0-install/bin" - echo "##vso[task.setvariable variable=LLVM_SYS_80_PREFIX]C:\\projects\\deps\\llvm-8.0.0-install" - fi - displayName: "Install LLVM (Windows)" + # - bash: | + # set -ex + # if [ -x "`command -v llvm-config`" ]; then + # echo `command -v cmake` `llvm-config --version` installed + # else + # mkdir C:\projects\deps + # cd C:\projects\deps + # curl -OL https://github.com/wasmerio/windows-llvm-build/releases/download/v8.0.0/llvm-8.0.0-install.zip + # 7z x llvm-8.0.0-install.zip + # echo "##vso[task.prependpath]/c/projects/deps/llvm-8.0.0-install/bin" + # echo "##vso[task.setvariable variable=LLVM_SYS_80_PREFIX]C:\\projects\\deps\\llvm-8.0.0-install" + # fi + # displayName: "Install LLVM (Windows)" + # condition: eq(variables['Agent.OS'], 'Windows_NT') + + - powershell: | + Invoke-WebRequest https://github.com/wasmerio/windows-llvm-build/releases/download/v8.0.0/llvm-8.0.0-install.zip + 7z x llvm-8.0.0-install.zip + Write-Host "##vso[task.prependpath]$pwd/llvm-8.0.0-install/bin" + Write-Host "##vso[task.setvariable variable=LLVM_SYS_80_PREFIX;]$pwd/llvm-8.0.0-install/" + displayName: Install LLVM (Windows) condition: eq(variables['Agent.OS'], 'Windows_NT') - bash: | From 89653145295d6c197512f244121c993d17c8cb13 Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 1 Sep 2019 11:15:35 -0700 Subject: [PATCH 74/90] Trying to fix pipelines --- .azure/install-llvm.yml | 26 ++++++++++---------------- .azure/install-rust.yml | 18 +++++++++--------- azure-pipelines.yml | 14 +++++++------- 3 files changed, 26 insertions(+), 32 deletions(-) diff --git a/.azure/install-llvm.yml b/.azure/install-llvm.yml index 4971ab36679..5b01ee7b9d9 100644 --- a/.azure/install-llvm.yml +++ b/.azure/install-llvm.yml @@ -29,24 +29,18 @@ steps: displayName: "Install LLVM (Linux)" condition: eq(variables['Agent.OS'], 'Linux') - # - bash: | - # set -ex - # if [ -x "`command -v llvm-config`" ]; then - # echo `command -v cmake` `llvm-config --version` installed - # else - # mkdir C:\projects\deps - # cd C:\projects\deps - # curl -OL https://github.com/wasmerio/windows-llvm-build/releases/download/v8.0.0/llvm-8.0.0-install.zip - # 7z x llvm-8.0.0-install.zip - # echo "##vso[task.prependpath]/c/projects/deps/llvm-8.0.0-install/bin" - # echo "##vso[task.setvariable variable=LLVM_SYS_80_PREFIX]C:\\projects\\deps\\llvm-8.0.0-install" - # fi - # displayName: "Install LLVM (Windows)" - # condition: eq(variables['Agent.OS'], 'Windows_NT') + - bash: | + set -ex + curl -OL https://github.com/wasmerio/windows-llvm-build/releases/download/v8.0.0/llvm-8.0.0-install.zip + 7z x llvm-8.0.0-install.zip + llvm=`pwd`/llvm-8.0.0-install + echo "##vso[task.prependpath]$llvm/bin" + echo "##vso[task.setvariable variable=LLVM_SYS_80_PREFIX;]$llvm" + displayName: "Install LLVM (Windows)" + condition: eq(variables['Agent.OS'], 'Windows_NT') + # Just to make sure the paths and vars are set properly - powershell: | - Invoke-WebRequest https://github.com/wasmerio/windows-llvm-build/releases/download/v8.0.0/llvm-8.0.0-install.zip - 7z x llvm-8.0.0-install.zip Write-Host "##vso[task.prependpath]$pwd/llvm-8.0.0-install/bin" Write-Host "##vso[task.setvariable variable=LLVM_SYS_80_PREFIX;]$pwd/llvm-8.0.0-install/" displayName: Install LLVM (Windows) diff --git a/.azure/install-rust.yml b/.azure/install-rust.yml index b26aca87e86..243cb7bf9d7 100644 --- a/.azure/install-rust.yml +++ b/.azure/install-rust.yml @@ -6,15 +6,15 @@ # Wasm-bindgen template: https://github.com/rustwasm/wasm-bindgen/blob/master/ci/azure-install-rust.yml steps: - - bash: | - set -ex - brew install openssl curl - brew link openssl --force - echo "##vso[task.prependpath]/usr/local/opt/openssl/bin" - echo "##vso[task.setvariable variable=LDFLAGS;]-L/usr/local/opt/openssl/lib" - echo "##vso[task.setvariable variable=CPPFLAGS;]-I/usr/local/opt/openssl/include" - displayName: "Fix Cargo SSL (macOS)" - condition: eq(variables['Agent.OS'], 'Darwin') + # - bash: | + # set -ex + # brew install openssl@1.1 curl + # brew link openssl@1.1 --force + # echo "##vso[task.prependpath]/usr/local/opt/openssl/bin" + # echo "##vso[task.setvariable variable=LDFLAGS;]-L/usr/local/opt/openssl/lib" + # echo "##vso[task.setvariable variable=CPPFLAGS;]-I/usr/local/opt/openssl/include" + # displayName: "Fix Cargo SSL (macOS)" + # condition: eq(variables['Agent.OS'], 'Darwin') - bash: | set -ex if [ -x "`command -v rustup`" ]; then diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d35b2960487..c4c75139329 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -29,10 +29,10 @@ jobs: matrix: linux: imageName: "ubuntu-16.04" - rust_toolchain: nightly-2019-07-04 + rust_toolchain: nightly-2019-08-15 mac: imageName: "macos-10.14" - rust_toolchain: nightly-2019-07-04 + rust_toolchain: nightly-2019-08-15 # By default schannel checks revocation of certificates unlike some other SSL # backends, but we've historically had problems on CI where a revocation # server goes down presumably. See #43333 for more info @@ -61,7 +61,7 @@ jobs: pool: vmImage: "ubuntu-16.04" variables: - rust_toolchain: nightly-2019-07-04 + rust_toolchain: nightly-2019-08-15 condition: in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying') steps: - checkout: self @@ -79,10 +79,10 @@ jobs: matrix: linux: imageName: "ubuntu-16.04" - rust_toolchain: nightly-2019-07-04 + rust_toolchain: nightly-2019-08-15 mac: imageName: "macos-10.14" - rust_toolchain: nightly-2019-07-04 + rust_toolchain: nightly-2019-08-15 MACOSX_DEPLOYMENT_TARGET: 10.10 windows: imageName: "vs2017-win2016" @@ -142,10 +142,10 @@ jobs: matrix: linux: imageName: "ubuntu-16.04" - rust_toolchain: nightly-2019-07-04 + rust_toolchain: nightly-2019-08-15 mac: imageName: "macos-10.14" - rust_toolchain: nightly-2019-07-04 + rust_toolchain: nightly-2019-08-15 MACOSX_DEPLOYMENT_TARGET: 10.10 windows: imageName: "vs2017-win2016" From f0bd680343b76a74124b38bbaaecaa33fdd46a3d Mon Sep 17 00:00:00 2001 From: Patrick Ventuzelo Date: Mon, 2 Sep 2019 11:08:40 +0200 Subject: [PATCH 75/90] validate_wasm fuzzer --- fuzz/Cargo.toml | 6 ++++++ fuzz/README.md | 6 +++++- fuzz/fuzz_targets/validate_wasm.rs | 19 +++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 fuzz/fuzz_targets/validate_wasm.rs diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 5c37cb47ed3..8660fdd976b 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -10,6 +10,8 @@ cargo-fuzz = true [dependencies] wasmer-runtime = { path = "../lib/runtime" } +wasmer-runtime-core = { path = "../lib/runtime-core" } +wasmer = { path = "../" } libfuzzer-sys = { git = "https://github.com/rust-fuzz/libfuzzer-sys.git" } # Prevent this from interfering with workspaces @@ -19,3 +21,7 @@ members = ["."] [[bin]] name = "simple_instantiate" path = "fuzz_targets/simple_instantiate.rs" + +[[bin]] +name = "validate_wasm" +path = "fuzz_targets/validate_wasm.rs" \ No newline at end of file diff --git a/fuzz/README.md b/fuzz/README.md index cac0a320a54..dda80ce7a6c 100644 --- a/fuzz/README.md +++ b/fuzz/README.md @@ -10,12 +10,16 @@ $ cargo install cargo-fuzz `cargo-fuzz` is documented in the [Rust Fuzz Book](https://rust-fuzz.github.io/book/cargo-fuzz.html). -## Running a fuzzer +## Running a fuzzer (simple_instantiate, validate_wasm) Once `cargo-fuzz` is installed, you can run the `simple_instantiate` fuzzer with ```sh cargo fuzz run simple_instantiate ``` +or the `validate_wasm` fuzzer +```sh +cargo fuzz run validate_wasm +``` You should see output that looks something like this: diff --git a/fuzz/fuzz_targets/validate_wasm.rs b/fuzz/fuzz_targets/validate_wasm.rs new file mode 100644 index 00000000000..0b2b09ecbb5 --- /dev/null +++ b/fuzz/fuzz_targets/validate_wasm.rs @@ -0,0 +1,19 @@ +#![no_main] +#[macro_use] extern crate libfuzzer_sys; + +extern crate wasmer_runtime_core; +extern crate wasmer; + +use wasmer_runtime_core::{ + backend::{Features}, +}; + +fuzz_target!(|data: &[u8]| { + let _ = wasmer::utils::is_wasm_binary(data); + let _ = wasmer_runtime_core::validate_and_report_errors_with_features( + &data, + Features { + // modify those values to explore additionnal part of wasmer + simd: false, threads: false, }, + ); +}); \ No newline at end of file From 8a2017cce33475489125f656a8ac69389e35b353 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2019 09:11:25 +0000 Subject: [PATCH 76/90] Bump cbindgen from 0.9.0 to 0.9.1 Bumps [cbindgen](https://github.com/eqrion/cbindgen) from 0.9.0 to 0.9.1. - [Release notes](https://github.com/eqrion/cbindgen/releases) - [Changelog](https://github.com/eqrion/cbindgen/blob/master/CHANGES) - [Commits](https://github.com/eqrion/cbindgen/compare/v0.9.0...v0.9.1) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 12 ++++++------ lib/runtime-c-api/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4cd73718b45..b1b9eb0f95e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -173,16 +173,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cbindgen" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 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)", + "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)", "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1595,7 +1595,7 @@ dependencies = [ name = "wasmer-runtime-c-api" version = "0.6.0" dependencies = [ - "cbindgen 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cbindgen 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime 0.6.0", "wasmer-runtime-core 0.6.0", @@ -1788,7 +1788,7 @@ dependencies = [ "checksum capstone-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fae25eddcb80e24f98c35952c37a91ff7f8d0f60dbbdafb9763e8d5cc566b8d7" "checksum cargo_toml 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "097f5ce64ba566a83d9d914fd005de1e5937fdd57d8c5d99a7593040955d75a9" "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" -"checksum cbindgen 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7e19db9a3892c88c74cbbdcd218196068a928f1b60e736c448b13a1e81f277" +"checksum cbindgen 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9daec6140ab4dcd38c3dd57e580b59a621172a526ac79f1527af760a55afeafd" "checksum cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "b548a4ee81fccb95919d4e22cfea83c7693ebfd78f0495493178db20b3139da7" "checksum cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7fa24eb00d5ffab90eaeaf1092ac85c04c64aaf358ea6f84505b8116d24c6af" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" diff --git a/lib/runtime-c-api/Cargo.toml b/lib/runtime-c-api/Cargo.toml index c95442c625a..7744118534c 100644 --- a/lib/runtime-c-api/Cargo.toml +++ b/lib/runtime-c-api/Cargo.toml @@ -32,4 +32,4 @@ llvm-backend = ["wasmer-runtime/llvm", "wasmer-runtime/default-backend-llvm"] singlepass-backend = ["wasmer-runtime/singlepass", "wasmer-runtime/default-backend-singlepass"] [build-dependencies] -cbindgen = "0.9.0" +cbindgen = "0.9.1" From 616b768529f0b07efd472fe340f0b00a87a65d91 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2019 09:11:48 +0000 Subject: [PATCH 77/90] Bump winapi from 0.3.7 to 0.3.8 Bumps [winapi](https://github.com/retep998/winapi-rs) from 0.3.7 to 0.3.8. - [Release notes](https://github.com/retep998/winapi-rs/releases) - [Commits](https://github.com/retep998/winapi-rs/compare/0.3.7...0.3.8) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 46 ++++++++++++++-------------- lib/clif-backend/Cargo.toml | 2 +- lib/llvm-backend/Cargo.toml | 2 +- lib/runtime-core/Cargo.toml | 2 +- lib/wasi/Cargo.toml | 2 +- lib/win-exception-handler/Cargo.toml | 2 +- 6 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4cd73718b45..3baca4c34ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,7 +13,7 @@ name = "ansi_term" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -40,7 +40,7 @@ version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -474,7 +474,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -671,7 +671,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -716,7 +716,7 @@ 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.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -725,7 +725,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -825,7 +825,7 @@ dependencies = [ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -898,7 +898,7 @@ dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (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.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -961,7 +961,7 @@ dependencies = [ "libc 0.2.62 (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.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1047,7 +1047,7 @@ name = "remove_dir_all" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1277,7 +1277,7 @@ dependencies = [ "rand 0.7.0 (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)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1311,7 +1311,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.62 (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.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1411,7 +1411,7 @@ version = "2.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1466,7 +1466,7 @@ dependencies = [ "wasmer-runtime-core 0.6.0", "wasmer-win-exception-handler 0.6.0", "wasmparser 0.35.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1553,7 +1553,7 @@ dependencies = [ "wabt 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime-core 0.6.0", "wasmparser 0.35.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1626,7 +1626,7 @@ dependencies = [ "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.35.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1668,7 +1668,7 @@ dependencies = [ "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)", "wasmer-runtime-core 0.6.0", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1693,7 +1693,7 @@ dependencies = [ "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)", "wasmer-runtime-core 0.6.0", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1717,7 +1717,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1739,7 +1739,7 @@ name = "winapi-util" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1752,7 +1752,7 @@ name = "wincolor" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1764,7 +1764,7 @@ 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)", "rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] @@ -1942,7 +1942,7 @@ dependencies = [ "checksum wasmparser 0.35.3 (registry+https://github.com/rust-lang/crates.io-index)" = "099aaf77635ffad3d9ab57253c29b16a46e93755c3e54cfe33fb8cf4b54f760b" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" +"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" diff --git a/lib/clif-backend/Cargo.toml b/lib/clif-backend/Cargo.toml index d0bf64d7b5b..a07c86899e2 100644 --- a/lib/clif-backend/Cargo.toml +++ b/lib/clif-backend/Cargo.toml @@ -34,7 +34,7 @@ version = "0.11.2" version = "0.0.7" [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3.7", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] } +winapi = { version = "0.3.8", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] } wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.6.0" } [features] diff --git a/lib/llvm-backend/Cargo.toml b/lib/llvm-backend/Cargo.toml index 043f6bfe6bb..56adae97b4d 100644 --- a/lib/llvm-backend/Cargo.toml +++ b/lib/llvm-backend/Cargo.toml @@ -24,7 +24,7 @@ features = ["llvm8-0", "target-x86"] nix = "0.15.0" [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3.7", features = ["memoryapi"] } +winapi = { version = "0.3.8", features = ["memoryapi"] } [build-dependencies] cc = "1.0" diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml index b22515fe047..6c31cf5f5cf 100644 --- a/lib/runtime-core/Cargo.toml +++ b/lib/runtime-core/Cargo.toml @@ -41,7 +41,7 @@ version = "0.5.6" version = "0.8.1" [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3.7", features = ["memoryapi"] } +winapi = { version = "0.3.8", features = ["memoryapi"] } [dev-dependencies] field-offset = "0.1.1" diff --git a/lib/wasi/Cargo.toml b/lib/wasi/Cargo.toml index 26a09c5ba83..86801f5e3e7 100644 --- a/lib/wasi/Cargo.toml +++ b/lib/wasi/Cargo.toml @@ -18,4 +18,4 @@ byteorder = "1.3.2" time = "0.1.42" [target.'cfg(windows)'.dependencies] -winapi = "0.3.7" +winapi = "0.3.8" diff --git a/lib/win-exception-handler/Cargo.toml b/lib/win-exception-handler/Cargo.toml index 17d1bfc3f09..b076088b35a 100644 --- a/lib/win-exception-handler/Cargo.toml +++ b/lib/win-exception-handler/Cargo.toml @@ -9,7 +9,7 @@ edition = "2018" [target.'cfg(windows)'.dependencies] wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" } -winapi = { version = "0.3.7", features = ["winbase", "errhandlingapi", "minwindef", "minwinbase", "winnt"] } +winapi = { version = "0.3.8", features = ["winbase", "errhandlingapi", "minwindef", "minwinbase", "winnt"] } libc = "0.2.60" [build-dependencies] From 9ba77aa1fc6f253458e06cd598690b12b3364cbd Mon Sep 17 00:00:00 2001 From: Patrick Ventuzelo <9038181+pventuzelo@users.noreply.github.com> Date: Mon, 2 Sep 2019 11:14:05 +0200 Subject: [PATCH 78/90] [formating] add new line Cargo.toml --- fuzz/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 8660fdd976b..229a36e7f89 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -24,4 +24,4 @@ path = "fuzz_targets/simple_instantiate.rs" [[bin]] name = "validate_wasm" -path = "fuzz_targets/validate_wasm.rs" \ No newline at end of file +path = "fuzz_targets/validate_wasm.rs" From afa6d6f52cd9fce1b1e8a14176cccb04209532ba Mon Sep 17 00:00:00 2001 From: Patrick Ventuzelo <9038181+pventuzelo@users.noreply.github.com> Date: Mon, 2 Sep 2019 11:14:40 +0200 Subject: [PATCH 79/90] [formatting] add new line validate_wasm.rs --- fuzz/fuzz_targets/validate_wasm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzz/fuzz_targets/validate_wasm.rs b/fuzz/fuzz_targets/validate_wasm.rs index 0b2b09ecbb5..4f5662bc8a2 100644 --- a/fuzz/fuzz_targets/validate_wasm.rs +++ b/fuzz/fuzz_targets/validate_wasm.rs @@ -16,4 +16,4 @@ fuzz_target!(|data: &[u8]| { // modify those values to explore additionnal part of wasmer simd: false, threads: false, }, ); -}); \ No newline at end of file +}); From 4406fbb6f3cd8f737899a17173c7ac954df264cf Mon Sep 17 00:00:00 2001 From: Patrick Ventuzelo Date: Mon, 2 Sep 2019 12:12:35 +0200 Subject: [PATCH 80/90] replace panics with return Err() --- 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 06ca175000f..4f77ec68ec4 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -634,7 +634,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { if let Err(ref err) = result { match err { - RuntimeError::Trap { msg } => panic!("wasm trap occured: {}", msg), + RuntimeError::Trap { msg } => return Err(format!("wasm trap occured: {}", msg)), #[cfg(feature = "wasi")] RuntimeError::Error { data } => { if let Some(error_code) = data.downcast_ref::() { @@ -644,7 +644,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { #[cfg(not(feature = "wasi"))] RuntimeError::Error { .. } => (), } - panic!("error: {:?}", err) + return Err(format!("error: {:?}", err)) } } } else { From cdba7e55e516c2bc4601b9478aa27003c03b75c2 Mon Sep 17 00:00:00 2001 From: Patrick Ventuzelo <9038181+pventuzelo@users.noreply.github.com> Date: Tue, 3 Sep 2019 17:06:37 +0200 Subject: [PATCH 81/90] Update src/bin/wasmer.rs Co-Authored-By: Syrus Akbary --- 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 4f77ec68ec4..5d0f849c369 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -644,7 +644,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { #[cfg(not(feature = "wasi"))] RuntimeError::Error { .. } => (), } - return Err(format!("error: {:?}", err)) + return Err(format!("error: {:?}", err)); } } } else { From 7dd496c4909b7bf7d0f357bca28d5f256b6e9a64 Mon Sep 17 00:00:00 2001 From: Patrick Ventuzelo <9038181+pventuzelo@users.noreply.github.com> Date: Tue, 3 Sep 2019 17:06:56 +0200 Subject: [PATCH 82/90] Update src/bin/wasmer.rs Co-Authored-By: Syrus Akbary --- src/bin/wasmer.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 5d0f849c369..651981b3bbe 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -634,7 +634,9 @@ fn execute_wasm(options: &Run) -> Result<(), String> { if let Err(ref err) = result { match err { - RuntimeError::Trap { msg } => return Err(format!("wasm trap occured: {}", msg)), + RuntimeError::Trap { msg } => { + return Err(format!("wasm trap occured: {}", msg)) + } #[cfg(feature = "wasi")] RuntimeError::Error { data } => { if let Some(error_code) = data.downcast_ref::() { From 7fc8ac84a80b2ae90dda44b986ec320ef67004d2 Mon Sep 17 00:00:00 2001 From: Syrus Date: Tue, 3 Sep 2019 14:55:26 -0700 Subject: [PATCH 83/90] Add sccache directory cache just in case --- azure-pipelines.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c4c75139329..a8df51c943c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -42,6 +42,8 @@ jobs: rust_toolchain: stable pool: vmImage: $(imageName) + variables: + SCCACHE_DIR: $(Pipeline.Workspace)/.sccache condition: in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying') steps: - checkout: self @@ -50,6 +52,11 @@ jobs: - template: .azure/install-llvm.yml - template: .azure/install-sccache.yml - template: .azure/install-cmake.yml + - task: CacheBeta@0 + inputs: + key: sccache | $(Agent.OS) | Cargo.lock + path: $(SCCACHE_DIR) + displayName: Cache Cargo Target - bash: make test displayName: Tests (*nix) condition: and(succeeded(), not(eq(variables['Agent.OS'], 'Windows_NT'))) @@ -63,6 +70,8 @@ jobs: variables: rust_toolchain: nightly-2019-08-15 condition: in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying') + variables: + SCCACHE_DIR: $(Pipeline.Workspace)/.sccache steps: - checkout: self submodules: true @@ -70,6 +79,11 @@ jobs: - template: .azure/install-llvm.yml - template: .azure/install-sccache.yml - template: .azure/install-cmake.yml + - task: CacheBeta@0 + inputs: + key: sccache | $(Agent.OS) | Cargo.lock + path: $(SCCACHE_DIR) + displayName: Cache Cargo Target - bash: make check displayName: Check with Flags condition: and(succeeded(), not(eq(variables['Agent.OS'], 'Windows_NT'))) @@ -90,6 +104,8 @@ jobs: # RUSTFLAGS: -Ctarget-feature=+crt-static pool: vmImage: $(imageName) + variables: + SCCACHE_DIR: $(Pipeline.Workspace)/.sccache condition: in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying') steps: - checkout: self @@ -99,6 +115,11 @@ jobs: - template: .azure/install-sccache.yml - template: .azure/install-cmake.yml - template: .azure/install-innosetup.yml + - task: CacheBeta@0 + inputs: + key: sccache | $(Agent.OS) | Cargo.lock + path: $(SCCACHE_DIR) + displayName: Cache Cargo Target - bash: | mkdir -p artifacts displayName: Create Artifacts Dir @@ -153,6 +174,8 @@ jobs: # RUSTFLAGS: -Ctarget-feature=+crt-static pool: vmImage: $(imageName) + variables: + SCCACHE_DIR: $(Pipeline.Workspace)/.sccache condition: in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying') steps: - checkout: self @@ -161,6 +184,11 @@ jobs: # - template: .azure/install-llvm.yml - template: .azure/install-sccache.yml - template: .azure/install-cmake.yml + - task: CacheBeta@0 + inputs: + key: sccache | $(Agent.OS) | Cargo.lock + path: $(SCCACHE_DIR) + displayName: Cache Cargo Target - bash: | mkdir -p artifacts displayName: Create Artifacts Dir From d54712f73b38263713bb346ec1012925661ec633 Mon Sep 17 00:00:00 2001 From: Syrus Date: Tue, 3 Sep 2019 14:56:29 -0700 Subject: [PATCH 84/90] Fix azure linting --- azure-pipelines.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a8df51c943c..697341cb905 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -69,9 +69,8 @@ jobs: vmImage: "ubuntu-16.04" variables: rust_toolchain: nightly-2019-08-15 - condition: in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying') - variables: SCCACHE_DIR: $(Pipeline.Workspace)/.sccache + condition: in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying') steps: - checkout: self submodules: true From 4ce2e2c56d687f9a071ecc735ec8dc12fc3fc8d9 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 3 Sep 2019 15:20:36 -0700 Subject: [PATCH 85/90] cargo fmt + adjust comment. --- fuzz/fuzz_targets/simple_instantiate.rs | 8 +++----- fuzz/fuzz_targets/validate_wasm.rs | 25 +++++++++++++------------ 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/fuzz/fuzz_targets/simple_instantiate.rs b/fuzz/fuzz_targets/simple_instantiate.rs index 831bbb1a510..e4912546da6 100644 --- a/fuzz/fuzz_targets/simple_instantiate.rs +++ b/fuzz/fuzz_targets/simple_instantiate.rs @@ -1,11 +1,9 @@ #![no_main] -#[macro_use] extern crate libfuzzer_sys; +#[macro_use] +extern crate libfuzzer_sys; extern crate wasmer_runtime; -use wasmer_runtime::{ - instantiate, - imports, -}; +use wasmer_runtime::{imports, instantiate}; fuzz_target!(|data: &[u8]| { let import_object = imports! {}; diff --git a/fuzz/fuzz_targets/validate_wasm.rs b/fuzz/fuzz_targets/validate_wasm.rs index 4f5662bc8a2..f386105eccf 100644 --- a/fuzz/fuzz_targets/validate_wasm.rs +++ b/fuzz/fuzz_targets/validate_wasm.rs @@ -1,19 +1,20 @@ #![no_main] -#[macro_use] extern crate libfuzzer_sys; +#[macro_use] +extern crate libfuzzer_sys; -extern crate wasmer_runtime_core; extern crate wasmer; +extern crate wasmer_runtime_core; -use wasmer_runtime_core::{ - backend::{Features}, -}; +use wasmer_runtime_core::backend::Features; fuzz_target!(|data: &[u8]| { - let _ = wasmer::utils::is_wasm_binary(data); - let _ = wasmer_runtime_core::validate_and_report_errors_with_features( - &data, - Features { - // modify those values to explore additionnal part of wasmer - simd: false, threads: false, }, - ); + let _ = wasmer::utils::is_wasm_binary(data); + let _ = wasmer_runtime_core::validate_and_report_errors_with_features( + &data, + Features { + // Modify these values to explore additional parts of wasmer. + simd: false, + threads: false, + }, + ); }); From 1a35cdd4cd490ae49d2e646f1ec31f4c8228c56d Mon Sep 17 00:00:00 2001 From: Syrus Date: Tue, 3 Sep 2019 15:32:32 -0700 Subject: [PATCH 86/90] Trying to improve local cache dir --- .azure/install-sccache.yml | 7 +++++++ azure-pipelines.yml | 27 --------------------------- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/.azure/install-sccache.yml b/.azure/install-sccache.yml index dffbb13d335..fa46bf6b0b6 100644 --- a/.azure/install-sccache.yml +++ b/.azure/install-sccache.yml @@ -28,6 +28,7 @@ steps: - bash: | set -ex env + mkdir -p $SCCACHE_DIR SCCACHE_ERROR_LOG=`pwd`/sccache.log RUST_LOG=debug $RUSTC_WRAPPER --start-server $RUSTC_WRAPPER -s cat sccache.log @@ -35,3 +36,9 @@ steps: env: SCCACHE_AZURE_CONNECTION_STRING: $(SCCACHE_AZURE_CONNECTION_STRING) SCCACHE_AZURE_BLOB_CONTAINER: $(SCCACHE_AZURE_BLOB_CONTAINER) + SCCACHE_DIR: $(Pipeline.Workspace)/.sccache + - task: CacheBeta@0 + inputs: + key: sccache | $(Agent.OS) | Cargo.lock + path: $(Pipeline.Workspace)/.sccache + displayName: Cache Cargo Target diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 697341cb905..c4c75139329 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -42,8 +42,6 @@ jobs: rust_toolchain: stable pool: vmImage: $(imageName) - variables: - SCCACHE_DIR: $(Pipeline.Workspace)/.sccache condition: in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying') steps: - checkout: self @@ -52,11 +50,6 @@ jobs: - template: .azure/install-llvm.yml - template: .azure/install-sccache.yml - template: .azure/install-cmake.yml - - task: CacheBeta@0 - inputs: - key: sccache | $(Agent.OS) | Cargo.lock - path: $(SCCACHE_DIR) - displayName: Cache Cargo Target - bash: make test displayName: Tests (*nix) condition: and(succeeded(), not(eq(variables['Agent.OS'], 'Windows_NT'))) @@ -69,7 +62,6 @@ jobs: vmImage: "ubuntu-16.04" variables: rust_toolchain: nightly-2019-08-15 - SCCACHE_DIR: $(Pipeline.Workspace)/.sccache condition: in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying') steps: - checkout: self @@ -78,11 +70,6 @@ jobs: - template: .azure/install-llvm.yml - template: .azure/install-sccache.yml - template: .azure/install-cmake.yml - - task: CacheBeta@0 - inputs: - key: sccache | $(Agent.OS) | Cargo.lock - path: $(SCCACHE_DIR) - displayName: Cache Cargo Target - bash: make check displayName: Check with Flags condition: and(succeeded(), not(eq(variables['Agent.OS'], 'Windows_NT'))) @@ -103,8 +90,6 @@ jobs: # RUSTFLAGS: -Ctarget-feature=+crt-static pool: vmImage: $(imageName) - variables: - SCCACHE_DIR: $(Pipeline.Workspace)/.sccache condition: in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying') steps: - checkout: self @@ -114,11 +99,6 @@ jobs: - template: .azure/install-sccache.yml - template: .azure/install-cmake.yml - template: .azure/install-innosetup.yml - - task: CacheBeta@0 - inputs: - key: sccache | $(Agent.OS) | Cargo.lock - path: $(SCCACHE_DIR) - displayName: Cache Cargo Target - bash: | mkdir -p artifacts displayName: Create Artifacts Dir @@ -173,8 +153,6 @@ jobs: # RUSTFLAGS: -Ctarget-feature=+crt-static pool: vmImage: $(imageName) - variables: - SCCACHE_DIR: $(Pipeline.Workspace)/.sccache condition: in(variables['Build.SourceBranch'], 'refs/heads/master', 'refs/heads/staging', 'refs/heads/trying') steps: - checkout: self @@ -183,11 +161,6 @@ jobs: # - template: .azure/install-llvm.yml - template: .azure/install-sccache.yml - template: .azure/install-cmake.yml - - task: CacheBeta@0 - inputs: - key: sccache | $(Agent.OS) | Cargo.lock - path: $(SCCACHE_DIR) - displayName: Cache Cargo Target - bash: | mkdir -p artifacts displayName: Create Artifacts Dir From f55e58936d3d8fe013c9fcf506631b39ac90f42c Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 3 Sep 2019 16:12:30 -0700 Subject: [PATCH 87/90] Build API documentation with cargo doc. --- Makefile | 3 +++ azure-pipelines.yml | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/Makefile b/Makefile index 1dbb03d81b2..7e6a431d070 100644 --- a/Makefile +++ b/Makefile @@ -183,3 +183,6 @@ publish-release: # must install graphviz for `dot` 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 diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c4c75139329..ae5c64fc144 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -211,6 +211,24 @@ jobs: tag: dev assets: $(Build.ArtifactStagingDirectory) + - job: Docs + pool: + vmImage: "ubuntu-16.04" + variables: + rust_toolchain: nightly-2019-08-15 + steps: + - checkout: self + submodules: true + - template: .azure/install-rust.yml + - template: .azure/install-llvm.yml + - template: .azure/install-sccache.yml + - template: .azure/install-cmake.yml + - bash: | + make docs + displayName: Build documentation + variables: + rust_toolchain: stable + # We only run the pipelines on PRs to Master pr: - master From 5f1de897ad8a67d1ebec509b89c54cd6f22329dc Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 3 Sep 2019 16:13:41 -0700 Subject: [PATCH 88/90] Don't redefine "variables". --- azure-pipelines.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index ae5c64fc144..aad922544fa 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -226,8 +226,6 @@ jobs: - bash: | make docs displayName: Build documentation - variables: - rust_toolchain: stable # We only run the pipelines on PRs to Master pr: From f785fe2e956ca587e21474017a15dec56282b70d Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 3 Sep 2019 16:18:02 -0700 Subject: [PATCH 89/90] Add 'docs' to .PHONY. Fixes Makefile claiming that 'docs' is up to date because it thinks we're asking it to build 'docs' directory instead of simply running cargo for us. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7e6a431d070..d8553e592d9 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: spectests emtests clean build install lint precommit +.PHONY: spectests emtests clean build install lint precommit docs # Generate files generate-spectests: From d8471e2b6acf85ca2c5ec6af77c186864b7b5bdc Mon Sep 17 00:00:00 2001 From: Syrus Date: Tue, 3 Sep 2019 17:06:31 -0700 Subject: [PATCH 90/90] Improved docs with custom logo and favicon --- lib/clif-backend/src/lib.rs | 3 +++ lib/dev-utils/src/lib.rs | 3 +++ lib/emscripten/src/lib.rs | 3 +++ lib/kernel-loader/src/lib.rs | 3 +++ lib/kernel-net/src/lib.rs | 2 ++ lib/llvm-backend/src/lib.rs | 2 ++ lib/middleware-common-tests/src/lib.rs | 1 - lib/middleware-common/src/lib.rs | 3 +++ lib/runtime-abi/src/lib.rs | 4 ++++ lib/runtime-c-api/src/lib.rs | 3 +++ lib/runtime-core/build.rs | 1 - lib/runtime-core/src/lib.rs | 2 ++ lib/runtime-core/src/memory/mod.rs | 1 - lib/runtime-core/src/table/mod.rs | 1 - lib/runtime-core/src/types.rs | 1 - lib/runtime/src/cache.rs | 1 - lib/runtime/src/lib.rs | 3 +++ lib/singlepass-backend/src/codegen_x64.rs | 3 ++- lib/singlepass-backend/src/lib.rs | 2 ++ lib/singlepass-backend/src/machine.rs | 1 - lib/spectests/tests/spectest.rs | 1 - lib/wasi/src/lib.rs | 3 +++ lib/win-exception-handler/src/lib.rs | 3 +++ src/lib.rs | 3 +++ 24 files changed, 44 insertions(+), 9 deletions(-) diff --git a/lib/clif-backend/src/lib.rs b/lib/clif-backend/src/lib.rs index eed22d39ea7..60f19a877ed 100644 --- a/lib/clif-backend/src/lib.rs +++ b/lib/clif-backend/src/lib.rs @@ -7,6 +7,9 @@ unused_unsafe, unreachable_patterns )] +#![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")] + mod cache; mod code; mod libcalls; diff --git a/lib/dev-utils/src/lib.rs b/lib/dev-utils/src/lib.rs index 76ae6804fc7..2a470bba40d 100644 --- a/lib/dev-utils/src/lib.rs +++ b/lib/dev-utils/src/lib.rs @@ -1,2 +1,5 @@ +#![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 file_descriptor; pub mod stdio; diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index c09f9b772c3..ba25b4be82a 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -7,6 +7,9 @@ unused_unsafe, unreachable_patterns )] +#![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")] + #[macro_use] extern crate wasmer_runtime_core; diff --git a/lib/kernel-loader/src/lib.rs b/lib/kernel-loader/src/lib.rs index 51ca6c7da54..37f51a424ce 100644 --- a/lib/kernel-loader/src/lib.rs +++ b/lib/kernel-loader/src/lib.rs @@ -1,3 +1,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 service; use service::{ImportInfo, LoadProfile, RunProfile, ServiceContext, TableEntryRequest}; diff --git a/lib/kernel-net/src/lib.rs b/lib/kernel-net/src/lib.rs index 4686867a7ce..cc6f918204b 100644 --- a/lib/kernel-net/src/lib.rs +++ b/lib/kernel-net/src/lib.rs @@ -1,5 +1,7 @@ #![cfg(all(target_arch = "wasm32", target_os = "wasi"))] #![feature(wasi_ext)] +#![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")] use std::cell::RefCell; use std::fs::File; diff --git a/lib/llvm-backend/src/lib.rs b/lib/llvm-backend/src/lib.rs index 480be9711c6..8194f797a45 100644 --- a/lib/llvm-backend/src/lib.rs +++ b/lib/llvm-backend/src/lib.rs @@ -8,6 +8,8 @@ )] #![cfg_attr(not(target_os = "windows"), deny(dead_code))] #![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")] mod backend; mod code; diff --git a/lib/middleware-common-tests/src/lib.rs b/lib/middleware-common-tests/src/lib.rs index 31b3e1065f9..0b6754c5f65 100644 --- a/lib/middleware-common-tests/src/lib.rs +++ b/lib/middleware-common-tests/src/lib.rs @@ -148,5 +148,4 @@ mod tests { // verify it used the correct number of points assert_eq!(get_points_used(&instance), 109); // Used points will be slightly more than `limit` because of the way we do gas checking. } - } diff --git a/lib/middleware-common/src/lib.rs b/lib/middleware-common/src/lib.rs index 929558f252e..c7900c83a73 100644 --- a/lib/middleware-common/src/lib.rs +++ b/lib/middleware-common/src/lib.rs @@ -7,5 +7,8 @@ unused_unsafe, unreachable_patterns )] +#![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 call_trace; pub mod metering; diff --git a/lib/runtime-abi/src/lib.rs b/lib/runtime-abi/src/lib.rs index 237e351b148..84923b43782 100644 --- a/lib/runtime-abi/src/lib.rs +++ b/lib/runtime-abi/src/lib.rs @@ -1,4 +1,8 @@ #![deny(dead_code, unused_imports, unused_variables, unused_unsafe, unreachable_patterns)] + +#![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(not(target_os = "windows"))] #[macro_use] extern crate failure; diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 0fde6d33094..4dae18cd590 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -1,3 +1,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")] + //! # Wasmer Runtime C API //! //! Wasmer is a standalone JIT WebAssembly runtime, aiming to be fully diff --git a/lib/runtime-core/build.rs b/lib/runtime-core/build.rs index 35aafc83511..81884f0e18b 100644 --- a/lib/runtime-core/build.rs +++ b/lib/runtime-core/build.rs @@ -38,6 +38,5 @@ fn main() { .file("image-loading-macos-x86-64.s") .compile("image-loading"); } else { - } } diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index 2bc6c7693a3..fa4450693ee 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -8,6 +8,8 @@ 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")] #[cfg(test)] #[macro_use] diff --git a/lib/runtime-core/src/memory/mod.rs b/lib/runtime-core/src/memory/mod.rs index a7510b818a3..75e9ea007dc 100644 --- a/lib/runtime-core/src/memory/mod.rs +++ b/lib/runtime-core/src/memory/mod.rs @@ -363,5 +363,4 @@ mod memory_tests { "Max number of pages is required for shared memory" ) } - } diff --git a/lib/runtime-core/src/table/mod.rs b/lib/runtime-core/src/table/mod.rs index 1c97b89f374..2e11507b1de 100644 --- a/lib/runtime-core/src/table/mod.rs +++ b/lib/runtime-core/src/table/mod.rs @@ -165,5 +165,4 @@ mod table_tests { .unwrap(); assert_eq!(table.size(), 10); } - } diff --git a/lib/runtime-core/src/types.rs b/lib/runtime-core/src/types.rs index ad00a1588c0..ab7c023a84b 100644 --- a/lib/runtime-core/src/types.rs +++ b/lib/runtime-core/src/types.rs @@ -590,5 +590,4 @@ mod tests { f64::from_native(f64::from_binary((yf64).to_native().to_binary())) ); } - } diff --git a/lib/runtime/src/cache.rs b/lib/runtime/src/cache.rs index 8fd5219a14b..fe39b512aea 100644 --- a/lib/runtime/src/cache.rs +++ b/lib/runtime/src/cache.rs @@ -173,5 +173,4 @@ mod tests { // verify it works assert_eq!(value, 43); } - } diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index 5b3ba852689..9495dcb346a 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -7,6 +7,9 @@ unused_unsafe, unreachable_patterns )] +#![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")] + //! Wasmer-runtime is a library that makes embedding WebAssembly //! in your application easy, efficient, and safe. //! diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 7f966eaa5ab..e069dfeeb0a 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -1318,7 +1318,8 @@ impl X64FunctionCode { } m.state .stack_values - .push(MachineValue::CopyStackBPRelative(offset)); // TODO: Read value at this offset + .push(MachineValue::CopyStackBPRelative(offset)); + // TODO: Read value at this offset } _ => { m.state.stack_values.push(MachineValue::Undefined); diff --git a/lib/singlepass-backend/src/lib.rs b/lib/singlepass-backend/src/lib.rs index e749e5a22ff..ccea7502ee9 100644 --- a/lib/singlepass-backend/src/lib.rs +++ b/lib/singlepass-backend/src/lib.rs @@ -8,6 +8,8 @@ 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")] #[cfg(not(any( all(target_os = "macos", target_arch = "x86_64"), diff --git a/lib/singlepass-backend/src/machine.rs b/lib/singlepass-backend/src/machine.rs index 1535ef8530a..a0793f37983 100644 --- a/lib/singlepass-backend/src/machine.rs +++ b/lib/singlepass-backend/src/machine.rs @@ -502,5 +502,4 @@ mod test { machine.release_locations_keep_state(&mut assembler, &locs); } - } diff --git a/lib/spectests/tests/spectest.rs b/lib/spectests/tests/spectest.rs index b85b9b0fe8c..9cd18d636a8 100644 --- a/lib/spectests/tests/spectest.rs +++ b/lib/spectests/tests/spectest.rs @@ -1265,5 +1265,4 @@ mod tests { self.to_bits() == 0x7FF8_0000_0000_0000 || self.to_bits() == 0xFFF8_0000_0000_0000 } } - } diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index ac9b11a86b9..2bdca703cc7 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -7,6 +7,9 @@ unused_unsafe, unreachable_patterns )] +#![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(target = "windows")] extern crate winapi; diff --git a/lib/win-exception-handler/src/lib.rs b/lib/win-exception-handler/src/lib.rs index cf5e8396fc8..459fbe9914a 100644 --- a/lib/win-exception-handler/src/lib.rs +++ b/lib/win-exception-handler/src/lib.rs @@ -7,6 +7,9 @@ unused_unsafe, unreachable_patterns )] +#![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(windows)] mod exception_handling; diff --git a/src/lib.rs b/src/lib.rs index 3d0b047ead6..f4d0e03bb31 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,9 @@ unused_unsafe, unreachable_patterns )] +#![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")] + #[macro_use] extern crate wasmer_runtime_core; // extern crate wasmer_emscripten;