From b834b4ff36c25dc138ac130c5ecd3f8ab06cc195 Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 31 May 2019 15:36:08 +0800 Subject: [PATCH] Metering for LLVM. --- lib/llvm-backend/src/backend.rs | 23 +++++++++- lib/llvm-backend/src/code.rs | 72 +++++++++++++++++++++++++----- lib/llvm-backend/src/intrinsics.rs | 40 ++++++++++++++++- lib/llvm-backend/src/lib.rs | 2 +- lib/runtime-abi/Cargo.toml | 5 --- src/bin/wasmer.rs | 20 ++++++--- 6 files changed, 138 insertions(+), 24 deletions(-) diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index 7a8c6c64a..4824141a6 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -24,6 +24,7 @@ use wasmer_runtime_core::{ CacheGen, RunnableModule, }, cache::Error as CacheError, + codegen::BkptInfo, module::ModuleInfo, structures::TypedIndex, typed_func::{Wasm, WasmTrapInfo}, @@ -190,6 +191,8 @@ fn get_callbacks() -> Callbacks { fn_name!("vm.exception.trap") => throw_trap as _, + fn_name!("vm.breakpoint") => vm_breakpoint as _, + _ => ptr::null(), } } @@ -209,6 +212,19 @@ fn get_callbacks() -> Callbacks { } } +unsafe extern "C" fn vm_breakpoint(_ctx: &mut vm::Ctx, breakpoints: *const Vec>, index: u32) -> i32 { + unsafe extern "C" fn do_throw() -> ! { + let ptr: *mut i32 = ::std::ptr::null_mut(); + *ptr = 42; + ::std::process::abort(); + } + let breakpoints: &Vec<_> = &*breakpoints; + breakpoints[index as usize](BkptInfo { + throw: do_throw, + }); + 0 +} + pub enum Buffer { LlvmMemory(MemoryBuffer), Memory(Memory), @@ -231,10 +247,11 @@ pub struct LLVMBackend { module: *mut LLVMModule, #[allow(dead_code)] buffer: Arc, + breakpoints: Box>>, } impl LLVMBackend { - pub fn new(module: Module, _intrinsics: Intrinsics) -> (Self, LLVMCache) { + pub fn new(module: Module, _intrinsics: Intrinsics, breakpoints: Box>>) -> (Self, LLVMCache) { Target::initialize_x86(&InitializationConfig { asm_parser: true, asm_printer: true, @@ -289,12 +306,13 @@ impl LLVMBackend { Self { module, buffer: Arc::clone(&buffer), + breakpoints, }, LLVMCache { buffer }, ) } - pub unsafe fn from_buffer(memory: Memory) -> Result<(Self, LLVMCache), String> { + pub unsafe fn from_buffer(memory: Memory, breakpoints: Box>>) -> Result<(Self, LLVMCache), String> { let callbacks = get_callbacks(); let mut module: *mut LLVMModule = ptr::null_mut(); @@ -318,6 +336,7 @@ impl LLVMBackend { Self { module, buffer: Arc::clone(&buffer), + breakpoints, }, LLVMCache { buffer }, )) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index aecf6fd74..4662ef345 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -398,6 +398,7 @@ pub struct LLVMFunctionCodeGenerator { num_params: usize, ctx: Option>, unreachable_depth: usize, + breakpoints: Option>>>, } impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { @@ -470,13 +471,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } fn feed_event(&mut self, event: Event, module_info: &ModuleInfo) -> Result<(), CodegenError> { - let op = match event { - Event::Wasm(x) => x, - Event::WasmOwned(ref x) => x, - Event::Internal(_x) => { + match event { + Event::Internal(InternalEvent::FunctionBegin(_)) | Event::Internal(InternalEvent::FunctionEnd) => { return Ok(()); } - }; + _ => {} + } let mut state = &mut self.state; let builder = self.builder.as_ref().unwrap(); @@ -489,6 +489,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let mut ctx = self.ctx.as_mut().unwrap(); if !state.reachable { + let op = match event { + Event::Wasm(x) => x, + Event::WasmOwned(ref x) => x, + Event::Internal(_x) => { + return Ok(()); + } + }; match *op { Operator::Block { ty: _ } | Operator::Loop { ty: _ } | Operator::If { ty: _ } => { self.unreachable_depth += 1; @@ -511,6 +518,44 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } } + let op = match event { + Event::Wasm(x) => x, + Event::WasmOwned(ref x) => x, + Event::Internal(x) => { + match x { + InternalEvent::Breakpoint(handler) => { + let mut breakpoints = self.breakpoints.as_mut().unwrap(); + breakpoints.push(handler); + let ptr: *mut Vec<_> = &mut **breakpoints; + let ptr_const = intrinsics + .i64_ty + .const_int(ptr as usize as u64, false) + .as_basic_value_enum(); + builder.build_call( + intrinsics.breakpoint, + &[ctx.basic(), ptr_const, intrinsics + .i32_ty + .const_int((breakpoints.len() - 1) as u64, false) + .as_basic_value_enum()], + &state.var_name(), + ); + }, + InternalEvent::GetInternal(index) => { + let ptr = ctx.internal_pointer(index as usize, intrinsics); + let value = builder.build_load(ptr, "internal_value"); + state.push1(value); + } + InternalEvent::SetInternal(index) => { + let value = state.pop1()?; + let ptr = ctx.internal_pointer(index as usize, intrinsics); + builder.build_store(ptr, value); + } + _ => {} + } + return Ok(()); + } + }; + match *op { /*************************** * Control Flow instructions. @@ -2508,16 +2553,18 @@ impl ModuleCodeGenerator fn next_function(&mut self) -> Result<&mut LLVMFunctionCodeGenerator, CodegenError> { // Creates a new function and returns the function-scope code generator for it. - let (context, builder, intrinsics) = match self.functions.last_mut() { + let (context, builder, intrinsics, breakpoints) = match self.functions.last_mut() { Some(x) => ( x.context.take().unwrap(), x.builder.take().unwrap(), x.intrinsics.take().unwrap(), + x.breakpoints.take().unwrap(), ), None => ( self.context.take().unwrap(), self.builder.take().unwrap(), self.intrinsics.take().unwrap(), + Box::new(Vec::new()), ), }; @@ -2576,6 +2623,7 @@ impl ModuleCodeGenerator num_params, ctx: None, unreachable_depth: 0, + breakpoints: Some(breakpoints), }; self.functions.push(code); Ok(self.functions.last_mut().unwrap()) @@ -2585,16 +2633,18 @@ impl ModuleCodeGenerator mut self, module_info: &ModuleInfo, ) -> Result<(LLVMBackend, Box), CodegenError> { - let (context, builder, intrinsics) = match self.functions.last_mut() { + let (context, builder, intrinsics, breakpoints) = match self.functions.last_mut() { Some(x) => ( x.context.take().unwrap(), x.builder.take().unwrap(), x.intrinsics.take().unwrap(), + x.breakpoints.take().unwrap(), ), None => ( self.context.take().unwrap(), self.builder.take().unwrap(), self.intrinsics.take().unwrap(), + Box::new(Vec::new()), ), }; self.context = Some(context); @@ -2625,7 +2675,7 @@ impl ModuleCodeGenerator // self.module.print_to_stderr(); - let (backend, cache_gen) = LLVMBackend::new(self.module, self.intrinsics.take().unwrap()); + let (backend, cache_gen) = LLVMBackend::new(self.module, self.intrinsics.take().unwrap(), breakpoints); Ok((backend, Box::new(cache_gen))) } @@ -2657,7 +2707,9 @@ impl ModuleCodeGenerator Ok(()) } - unsafe fn from_cache(artifact: Artifact, _: Token) -> Result { + unsafe fn from_cache(_artifact: Artifact, _: Token) -> Result { + Err(CacheError::Unknown("caching is broken for LLVM backend".into())) + /* let (info, _, memory) = artifact.consume(); let (backend, cache_gen) = LLVMBackend::from_buffer(memory).map_err(CacheError::DeserializeError)?; @@ -2667,6 +2719,6 @@ impl ModuleCodeGenerator cache_gen: Box::new(cache_gen), info, - }) + })*/ } } diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index 2198821ed..c3982857c 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -113,6 +113,8 @@ pub struct Intrinsics { pub memory_size_static_import: FunctionValue, pub memory_size_shared_import: FunctionValue, + pub breakpoint: FunctionValue, + pub throw_trap: FunctionValue, pub ctx_ptr_ty: PointerType, @@ -163,7 +165,7 @@ impl Intrinsics { let stack_lower_bound_ty = i8_ty; let memory_base_ty = i8_ty; let memory_bound_ty = void_ty; - let internals_ty = void_ty; + let internals_ty = i64_ty; let local_function_ty = i8_ptr_ty; let anyfunc_ty = context.struct_type( @@ -250,6 +252,8 @@ impl Intrinsics { let ret_i1_take_i1_i1 = i1_ty.fn_type(&[i1_ty_basic, i1_ty_basic], false); + let ret_i32_take_ctx_i64_i32 = i32_ty.fn_type(&[ctx_ptr_ty.as_basic_type_enum(), i64_ty_basic, i32_ty_basic], false); + Self { ctlz_i32: module.add_function("llvm.ctlz.i32", ret_i32_take_i32_i1, None), ctlz_i64: module.add_function("llvm.ctlz.i64", ret_i64_take_i64_i1, None), @@ -382,6 +386,11 @@ impl Intrinsics { ret_i32_take_ctx_i32, None, ), + breakpoint: module.add_function( + "vm.breakpoint", + ret_i32_take_ctx_i64_i32, + None, + ), throw_trap: module.add_function( "vm.exception.trap", void_ty.fn_type(&[i32_ty_basic], false), @@ -432,6 +441,7 @@ pub struct CtxType<'a> { cached_tables: HashMap, cached_sigindices: HashMap, cached_globals: HashMap, + cached_internals: HashMap, cached_imported_functions: HashMap, _phantom: PhantomData<&'a FunctionValue>, @@ -457,6 +467,7 @@ impl<'a> CtxType<'a> { cached_tables: HashMap::new(), cached_sigindices: HashMap::new(), cached_globals: HashMap::new(), + cached_internals: HashMap::new(), cached_imported_functions: HashMap::new(), _phantom: PhantomData, @@ -680,6 +691,33 @@ impl<'a> CtxType<'a> { }) } + pub fn internal_pointer(&mut self, index: usize, intrinsics: &Intrinsics) -> PointerValue { + let (cached_internals, ctx_ptr_value, _info, cache_builder) = ( + &mut self.cached_internals, + self.ctx_ptr_value, + self.info, + &self.cache_builder, + ); + *cached_internals.entry(index).or_insert_with(|| { + let array_ptr_ptr = unsafe { + cache_builder.build_struct_gep( + ctx_ptr_value, + offset_to_index(Ctx::offset_internals()), + "internals_array_ptr_ptr", + ) + }; + let array_ptr = cache_builder.build_load(array_ptr_ptr, "internals_array_ptr").into_pointer_value(); + let const_index = intrinsics.i32_ty.const_int(index as u64, false); + unsafe { + cache_builder.build_in_bounds_gep( + array_ptr, + &[const_index], + "element_ptr", + ) + } + }) + } + pub fn global_cache(&mut self, index: GlobalIndex, intrinsics: &Intrinsics) -> GlobalCache { let (cached_globals, ctx_ptr_value, info, cache_builder) = ( &mut self.cached_globals, diff --git a/lib/llvm-backend/src/lib.rs b/lib/llvm-backend/src/lib.rs index 6d8816af8..8c8685d79 100644 --- a/lib/llvm-backend/src/lib.rs +++ b/lib/llvm-backend/src/lib.rs @@ -2,7 +2,7 @@ #![cfg_attr(nightly, feature(unwind_attributes))] mod backend; -mod code; +pub mod code; mod intrinsics; mod platform; mod read_info; diff --git a/lib/runtime-abi/Cargo.toml b/lib/runtime-abi/Cargo.toml index b989618a0..865d67f18 100644 --- a/lib/runtime-abi/Cargo.toml +++ b/lib/runtime-abi/Cargo.toml @@ -16,15 +16,10 @@ tar = "0.4" wasmparser = "0.30.0" zstd = "0.4" -<<<<<<< HEAD -[target.'cfg(unix)'.dependencies.zbox] -git = "https://github.com/zboxfs/zbox" -======= # [target.'cfg(unix)'.dependencies.zbox] # git = "https://github.com/wasmerio/zbox" # branch = "bundle-libsodium" # features = ["libsodium-bundled"] ->>>>>>> origin/master [dev-dependencies] tempdir = "0.3" diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 9a5e6916c..3122631d3 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -16,8 +16,9 @@ use structopt::StructOpt; use wasmer::*; use wasmer_clif_backend::CraneliftCompiler; #[cfg(feature = "backend:llvm")] -use wasmer_llvm_backend::LLVMCompiler; -#[cfg(feature = "backend:singlepass")] +use wasmer_llvm_backend::{ + code::LLVMModuleCodeGenerator, +}; use wasmer_middleware_common::metering::Metering; use wasmer_runtime::{ cache::{Cache as BaseCache, FileSystemCache, WasmHash, WASMER_VERSION_HASH}, @@ -336,7 +337,16 @@ fn execute_wasm(options: &Run) -> Result<(), String> { 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()), + Backend::LLVM => { + let c: StreamingCompiler = StreamingCompiler::new(|| { + let mut chain = MiddlewareChain::new(); + if let Some(limit) = options.instruction_limit { + chain.push(Metering::new(limit)); + } + chain + }); + Box::new(c) + }, #[cfg(not(feature = "backend:llvm"))] Backend::LLVM => return Err("the llvm backend is not enabled".to_string()), }; @@ -527,11 +537,11 @@ fn execute_wasm(options: &Run) -> Result<(), String> { .map(|arg| arg.as_str()) .map(|x| Value::I32(x.parse().unwrap())) .collect(); - instance + println!("{:?}", instance .dyn_func("main") .map_err(|e| format!("{:?}", e))? .call(&args) - .map_err(|e| format!("{:?}", e))?; + .map_err(|e| format!("{:?}", e))?); } }