From 17eada53f34a81e56157f033e0ac2c235d5628ce Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Fri, 8 Mar 2019 15:15:16 -0800 Subject: [PATCH] feat(runtime) Get ready for tiering (#257) * Add local_function field to context * Add local call indirection to llvm * local call indirection * Fix vm test * Fix cranelift local call indirection * Fix unwinding on nightly --- Cargo.lock | 3 ++ lib/clif-backend/src/func_env.rs | 31 ++++++++++++++++++-- lib/llvm-backend/Cargo.toml | 1 + lib/llvm-backend/build.rs | 6 ++++ lib/llvm-backend/src/code.rs | 5 ++-- lib/llvm-backend/src/intrinsics.rs | 39 +++++++++++++++++++++++-- lib/llvm-backend/src/lib.rs | 2 ++ lib/llvm-backend/src/platform/unix.rs | 6 ++-- lib/runtime-core/src/backing.rs | 20 +++++++++++-- lib/runtime-core/src/sys/unix/memory.rs | 2 ++ lib/runtime-core/src/vm.rs | 14 +++++++++ 11 files changed, 118 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2ee89b12858..b6a7f4718e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,3 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. [[package]] name = "aho-corasick" version = "0.6.10" @@ -1344,6 +1346,7 @@ dependencies = [ "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/lib/clif-backend/src/func_env.rs b/lib/clif-backend/src/func_env.rs index b08f56dd241..8a65444b74c 100644 --- a/lib/clif-backend/src/func_env.rs +++ b/lib/clif-backend/src/func_env.rs @@ -445,6 +445,12 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { pos.ins().symbol_value(ir::types::I64, sig_index_global) + // let dynamic_sigindices_array_ptr = pos.ins().load( + // ptr_type, + // mflags, + + // ) + // let expected_sig = pos.ins().iconst(ir::types::I32, sig_index.index() as i64); // self.env.deduplicated[clif_sig_index] @@ -477,9 +483,10 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { call_args: &[ir::Value], ) -> cranelift_wasm::WasmResult { let callee_index: FuncIndex = Converter(clif_callee_index).into(); + let ptr_type = self.pointer_type(); match callee_index.local_or_import(&self.env.module.info) { - LocalOrImport::Local(_) => { + LocalOrImport::Local(local_function_index) => { // this is an internal function let vmctx = pos .func @@ -490,10 +497,28 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { args.push(vmctx); args.extend(call_args.iter().cloned()); - Ok(pos.ins().call(callee, &args)) + let sig_ref = pos.func.dfg.ext_funcs[callee].signature; + let function_ptr = { + let mflags = ir::MemFlags::trusted(); + + let function_array_ptr = pos.ins().load( + ptr_type, + mflags, + vmctx, + vm::Ctx::offset_local_functions() as i32, + ); + + pos.ins().load( + ptr_type, + mflags, + function_array_ptr, + (local_function_index.index() as i32) * 8, + ) + }; + + Ok(pos.ins().call_indirect(sig_ref, function_ptr, &args)) } LocalOrImport::Import(imported_func_index) => { - let ptr_type = self.pointer_type(); // this is an imported function let vmctx = pos.func.create_global_value(ir::GlobalValueData::VMContext); diff --git a/lib/llvm-backend/Cargo.toml b/lib/llvm-backend/Cargo.toml index e6f58e6e724..646bbd1578f 100644 --- a/lib/llvm-backend/Cargo.toml +++ b/lib/llvm-backend/Cargo.toml @@ -20,6 +20,7 @@ cc = "1.0" lazy_static = "1.2.0" regex = "1.1.0" semver = "0.9" +rustc_version = "0.2.3" [dev-dependencies] wabt = "0.7.4" diff --git a/lib/llvm-backend/build.rs b/lib/llvm-backend/build.rs index 062a5a5fed0..ed96cae9d4d 100644 --- a/lib/llvm-backend/build.rs +++ b/lib/llvm-backend/build.rs @@ -212,4 +212,10 @@ fn main() { .compile("llvm-backend"); println!("cargo:rustc-link-lib=static=llvm-backend"); + println!("cargo:rerun-if-changed=build.rs"); + + // Enable "nightly" cfg if the current compiler is nightly. + if rustc_version::version_meta().unwrap().channel == rustc_version::Channel::Nightly { + println!("cargo:rustc-cfg=nightly"); + } } diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 3d9f82153c3..173262b67be 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -664,14 +664,15 @@ fn parse_function( let call_site = match func_index.local_or_import(info) { LocalOrImport::Local(local_func_index) => { - let func_value = functions[local_func_index]; let params: Vec<_> = [ctx.basic()] .iter() .chain(state.peekn(func_sig.params().len())?.iter()) .map(|v| *v) .collect(); - builder.build_call(func_value, ¶ms, &state.var_name()) + let func_ptr = ctx.local_func(local_func_index, llvm_sig); + + builder.build_call(func_ptr, ¶ms, &state.var_name()) } LocalOrImport::Import(import_func_index) => { let (func_ptr_untyped, ctx_ptr) = ctx.imported_func(import_func_index); diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index 98c41326e93..ba1e3abd34c 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -3,7 +3,7 @@ use inkwell::{ builder::Builder, context::Context, module::Module, - types::{BasicType, FloatType, IntType, PointerType, StructType, VoidType}, + types::{BasicType, FloatType, FunctionType, IntType, PointerType, StructType, VoidType}, values::{ BasicValue, BasicValueEnum, FloatValue, FunctionValue, InstructionValue, IntValue, PointerValue, @@ -16,7 +16,8 @@ use wasmer_runtime_core::{ module::ModuleInfo, structures::TypedIndex, types::{ - GlobalIndex, ImportedFuncIndex, LocalOrImport, MemoryIndex, SigIndex, TableIndex, Type, + GlobalIndex, ImportedFuncIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex, + TableIndex, Type, }, }; @@ -161,6 +162,7 @@ impl Intrinsics { let imported_func_ty = context.struct_type(&[i8_ptr_ty_basic, ctx_ptr_ty.as_basic_type_enum()], false); let sigindex_ty = i32_ty; + let local_function_ty = i8_ptr_ty; let anyfunc_ty = context.struct_type( &[ @@ -203,6 +205,9 @@ impl Intrinsics { sigindex_ty .ptr_type(AddressSpace::Generic) .as_basic_type_enum(), + local_function_ty + .ptr_type(AddressSpace::Generic) + .as_basic_type_enum(), ], false, ); @@ -582,6 +587,36 @@ impl<'a> CtxType<'a> { ) } + pub fn local_func(&mut self, index: LocalFuncIndex, fn_ty: FunctionType) -> PointerValue { + let local_func_array_ptr_ptr = unsafe { + self.builder + .build_struct_gep(self.ctx_ptr_value, 8, "local_func_array_ptr_ptr") + }; + let local_func_array_ptr = self + .builder + .build_load(local_func_array_ptr_ptr, "local_func_array_ptr") + .into_pointer_value(); + let local_func_ptr_ptr = unsafe { + self.builder.build_in_bounds_gep( + local_func_array_ptr, + &[self + .intrinsics + .i32_ty + .const_int(index.index() as u64, false)], + "local_func_ptr_ptr", + ) + }; + let local_func_ptr = self + .builder + .build_load(local_func_ptr_ptr, "local_func_ptr") + .into_pointer_value(); + self.builder.build_pointer_cast( + local_func_ptr, + fn_ty.ptr_type(AddressSpace::Generic), + "local_func_ptr", + ) + } + pub fn dynamic_sigindex(&mut self, index: SigIndex) -> IntValue { let (cached_sigindices, builder, info, ctx_ptr_value, intrinsics, cache_builder) = ( &mut self.cached_sigindices, diff --git a/lib/llvm-backend/src/lib.rs b/lib/llvm-backend/src/lib.rs index d70f0f363ac..85bcc7e1976 100644 --- a/lib/llvm-backend/src/lib.rs +++ b/lib/llvm-backend/src/lib.rs @@ -1,3 +1,5 @@ +#![cfg_attr(nightly, feature(unwind_attributes))] + use inkwell::{ execution_engine::JitFunction, targets::{CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetMachine}, diff --git a/lib/llvm-backend/src/platform/unix.rs b/lib/llvm-backend/src/platform/unix.rs index c17f563595b..2267ab129e2 100644 --- a/lib/llvm-backend/src/platform/unix.rs +++ b/lib/llvm-backend/src/platform/unix.rs @@ -41,6 +41,7 @@ pub unsafe fn visit_fde(addr: *mut u8, size: usize, visitor: extern "C" fn(*mut } extern "C" { + #[cfg_attr(nightly, unwind(allowed))] fn throw_trap(ty: i32) -> !; } @@ -50,12 +51,13 @@ pub unsafe fn install_signal_handler() { SaFlags::SA_ONSTACK | SaFlags::SA_SIGINFO, SigSet::empty(), ); - sigaction(SIGFPE, &sa).unwrap(); - sigaction(SIGILL, &sa).unwrap(); + // sigaction(SIGFPE, &sa).unwrap(); + // sigaction(SIGILL, &sa).unwrap(); sigaction(SIGSEGV, &sa).unwrap(); sigaction(SIGBUS, &sa).unwrap(); } +#[cfg_attr(nightly, unwind(allowed))] extern "C" fn signal_trap_handler( signum: ::nix::libc::c_int, siginfo: *mut siginfo_t, diff --git a/lib/runtime-core/src/backing.rs b/lib/runtime-core/src/backing.rs index 33cd801821d..48f2d225678 100644 --- a/lib/runtime-core/src/backing.rs +++ b/lib/runtime-core/src/backing.rs @@ -10,8 +10,8 @@ use crate::{ table::Table, types::{ ImportedFuncIndex, ImportedGlobalIndex, ImportedMemoryIndex, ImportedTableIndex, - Initializer, LocalGlobalIndex, LocalMemoryIndex, LocalOrImport, LocalTableIndex, SigIndex, - Value, + Initializer, LocalFuncIndex, LocalGlobalIndex, LocalMemoryIndex, LocalOrImport, + LocalTableIndex, SigIndex, Value, }, vm, }; @@ -28,6 +28,7 @@ pub struct LocalBacking { pub(crate) vm_globals: BoxedMap, pub(crate) dynamic_sigindices: BoxedMap, + pub(crate) local_functions: BoxedMap, } // impl LocalBacking { @@ -51,6 +52,7 @@ impl LocalBacking { let vm_globals = Self::finalize_globals(&mut globals); let dynamic_sigindices = Self::generate_sigindices(&module.info); + let local_functions = Self::generate_local_functions(module); Self { memories, @@ -62,9 +64,23 @@ impl LocalBacking { vm_globals, dynamic_sigindices, + local_functions, } } + fn generate_local_functions(module: &ModuleInner) -> BoxedMap { + (0..module.info.func_assoc.len() - module.info.imported_functions.len()) + .map(|index| { + module + .func_resolver + .get(module, LocalFuncIndex::new(index)) + .unwrap() + .as_ptr() as *const _ + }) + .collect::>() + .into_boxed_map() + } + fn generate_sigindices(info: &ModuleInfo) -> BoxedMap { info.signatures .iter() diff --git a/lib/runtime-core/src/sys/unix/memory.rs b/lib/runtime-core/src/sys/unix/memory.rs index 338024d09d7..9ffb663ebb8 100644 --- a/lib/runtime-core/src/sys/unix/memory.rs +++ b/lib/runtime-core/src/sys/unix/memory.rs @@ -245,6 +245,7 @@ pub enum Protect { Read, ReadWrite, ReadExec, + ReadWriteExec, } impl Protect { @@ -254,6 +255,7 @@ impl Protect { Protect::Read => 1, Protect::ReadWrite => 1 | 2, Protect::ReadExec => 1 | 4, + Protect::ReadWriteExec => 1 | 2 | 4, } } diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index bc0aa71e841..508ca031b8e 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -40,6 +40,8 @@ pub struct Ctx { /// modules safely. pub(crate) dynamic_sigindices: *const SigId, + pub(crate) local_functions: *const *const Func, + local_backing: *mut LocalBacking, import_backing: *mut ImportBacking, module: *const ModuleInner, @@ -66,6 +68,7 @@ impl Ctx { imported_funcs: import_backing.vm_functions.as_mut_ptr(), dynamic_sigindices: local_backing.dynamic_sigindices.as_ptr(), + local_functions: local_backing.local_functions.as_ptr(), local_backing, import_backing, @@ -95,6 +98,7 @@ impl Ctx { imported_funcs: import_backing.vm_functions.as_mut_ptr(), dynamic_sigindices: local_backing.dynamic_sigindices.as_ptr(), + local_functions: local_backing.local_functions.as_ptr(), local_backing, import_backing, @@ -173,6 +177,10 @@ impl Ctx { pub fn offset_signatures() -> u8 { 7 * (mem::size_of::() as u8) } + + pub fn offset_local_functions() -> u8 { + 8 * (mem::size_of::() as u8) + } } enum InnerFunc {} @@ -363,6 +371,11 @@ mod vm_offset_tests { Ctx::offset_imported_funcs() as usize, offset_of!(Ctx => imported_funcs).get_byte_offset(), ); + + assert_eq!( + Ctx::offset_local_functions() as usize, + offset_of!(Ctx => local_functions).get_byte_offset(), + ); } #[test] @@ -470,6 +483,7 @@ mod vm_ctx_tests { vm_globals: Map::new().into_boxed_map(), dynamic_sigindices: Map::new().into_boxed_map(), + local_functions: Map::new().into_boxed_map(), }; let mut import_backing = ImportBacking { memories: Map::new().into_boxed_map(),