Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add caching support to llvm backend #367

Merged
merged 5 commits into from
Apr 19, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ All PRs to the Wasmer repository must add to this file.
Blocks of changes will separated by version increments.

## **[Unreleased]**
- [#367](https://github.com/wasmerio/wasmer/pull/367) Add caching support to the LLVM backend.
- [#366](https://github.com/wasmerio/wasmer/pull/366) Remove `UserTrapper` trait to fix [#365](https://github.com/wasmerio/wasmer/issues/365).
- [#348](https://github.com/wasmerio/wasmer/pull/348) Refactor internal runtime ↔️ backend abstraction.
- [#355](https://github.com/wasmerio/wasmer/pull/355) Misc changes to `Cargo.toml`s for publishing
Expand Down
8 changes: 1 addition & 7 deletions lib/clif-backend/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,12 @@ impl CacheGenerator {
}

impl CacheGen for CacheGenerator {
fn generate_cache(
&self,
module: &ModuleInner,
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), Error> {
let info = Box::new(module.info.clone());

fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), Error> {
// Clone the memory to a new location. This could take a long time,
// depending on the throughput of your memcpy implementation.
let compiled_code = (*self.memory).clone();

Ok((
info,
self.backend_cache.into_backend_data()?.into_boxed_slice(),
compiled_code,
))
Expand Down
27 changes: 16 additions & 11 deletions lib/llvm-backend/cpp/object_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,21 +175,26 @@ WasmModule::WasmModule(
callbacks_t callbacks
) : memory_manager(std::unique_ptr<MemoryManager>(new MemoryManager(callbacks)))
{
object_file = llvm::cantFail(llvm::object::ObjectFile::createObjectFile(llvm::MemoryBufferRef(
llvm::StringRef((const char *)object_start, object_size), "object"
)));


SymbolLookup symbol_resolver(callbacks);
runtime_dyld = std::unique_ptr<llvm::RuntimeDyld>(new llvm::RuntimeDyld(*memory_manager, symbol_resolver));
if (auto created_object_file = llvm::object::ObjectFile::createObjectFile(llvm::MemoryBufferRef(
llvm::StringRef((const char *)object_start, object_size), "object"
))) {
object_file = cantFail(std::move(created_object_file));
SymbolLookup symbol_resolver(callbacks);
runtime_dyld = std::unique_ptr<llvm::RuntimeDyld>(new llvm::RuntimeDyld(*memory_manager, symbol_resolver));

runtime_dyld->setProcessAllSections(true);
runtime_dyld->setProcessAllSections(true);

runtime_dyld->loadObject(*object_file);
runtime_dyld->finalizeWithMemoryManagerLocking();
runtime_dyld->loadObject(*object_file);
runtime_dyld->finalizeWithMemoryManagerLocking();

if (runtime_dyld->hasError()) {
std::cout << "RuntimeDyld error: " << (std::string)runtime_dyld->getErrorString() << std::endl;
abort();
if (runtime_dyld->hasError()) {
_init_failed = true;
return;
}
} else {
_init_failed = true;
}
}

Expand Down
5 changes: 5 additions & 0 deletions lib/llvm-backend/cpp/object_loader.hh
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ struct WasmModule

void *get_func(llvm::StringRef name) const;

bool _init_failed = false;
private:
std::unique_ptr<llvm::RuntimeDyld::MemoryManager> memory_manager;
std::unique_ptr<llvm::object::ObjectFile> object_file;
Expand All @@ -164,6 +165,10 @@ extern "C"
{
*module_out = new WasmModule(mem_ptr, mem_size, callbacks);

if ((*module_out)->_init_failed) {
return RESULT_OBJECT_LOAD_FAILURE;
}

return RESULT_OK;
}

Expand Down
90 changes: 83 additions & 7 deletions lib/llvm-backend/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,17 @@ use std::{
any::Any,
ffi::{c_void, CString},
mem,
ops::Deref,
ptr::{self, NonNull},
slice, str,
sync::Once,
sync::{Arc, Once},
};
use wasmer_runtime_core::{
backend::RunnableModule,
backend::{
sys::{Memory, Protect},
CacheGen, RunnableModule,
},
cache::Error as CacheError,
module::ModuleInfo,
structures::TypedIndex,
typed_func::{Wasm, WasmTrapInfo},
Expand Down Expand Up @@ -203,17 +208,32 @@ fn get_callbacks() -> Callbacks {
}
}

pub enum Buffer {
LlvmMemory(MemoryBuffer),
Memory(Memory),
}

impl Deref for Buffer {
type Target = [u8];
fn deref(&self) -> &[u8] {
match self {
Buffer::LlvmMemory(mem_buffer) => mem_buffer.as_slice(),
Buffer::Memory(memory) => unsafe { memory.as_slice() },
}
}
}

unsafe impl Send for LLVMBackend {}
unsafe impl Sync for LLVMBackend {}

pub struct LLVMBackend {
module: *mut LLVMModule,
#[allow(dead_code)]
memory_buffer: MemoryBuffer,
buffer: Arc<Buffer>,
}

impl LLVMBackend {
pub fn new(module: Module, _intrinsics: Intrinsics) -> Self {
pub fn new(module: Module, _intrinsics: Intrinsics) -> (Self, LLVMCache) {
Target::initialize_x86(&InitializationConfig {
asm_parser: true,
asm_printer: true,
Expand Down Expand Up @@ -262,10 +282,44 @@ impl LLVMBackend {
panic!("failed to load object")
}

Self {
module,
memory_buffer,
let buffer = Arc::new(Buffer::LlvmMemory(memory_buffer));

(
Self {
module,
buffer: Arc::clone(&buffer),
},
LLVMCache { buffer },
)
}

pub unsafe fn from_buffer(memory: Memory) -> Result<(Self, LLVMCache), String> {
let callbacks = get_callbacks();
let mut module: *mut LLVMModule = ptr::null_mut();

let slice = unsafe { memory.as_slice() };

let res = module_load(slice.as_ptr(), slice.len(), callbacks, &mut module);

if res != LLVMResult::OK {
return Err("failed to load object".to_string());
}

static SIGNAL_HANDLER_INSTALLED: Once = Once::new();

SIGNAL_HANDLER_INSTALLED.call_once(|| unsafe {
crate::platform::install_signal_handler();
});

let buffer = Arc::new(Buffer::Memory(memory));

Ok((
Self {
module,
buffer: Arc::clone(&buffer),
},
LLVMCache { buffer },
))
}
}

Expand Down Expand Up @@ -322,6 +376,28 @@ impl RunnableModule for LLVMBackend {
}
}

unsafe impl Send for LLVMCache {}
unsafe impl Sync for LLVMCache {}

pub struct LLVMCache {
buffer: Arc<Buffer>,
}

impl CacheGen for LLVMCache {
fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), CacheError> {
let mut memory = Memory::with_size_protect(self.buffer.len(), Protect::ReadWrite)
.map_err(CacheError::SerializeError)?;

let buffer = self.buffer.deref();

unsafe {
memory.as_slice_mut()[..buffer.len()].copy_from_slice(buffer);
}

Ok(([].as_ref().into(), memory))
}
}

#[cfg(feature = "disasm")]
unsafe fn disass_ptr(ptr: *const u8, size: usize, inst_count: usize) {
use capstone::arch::BuildsCapstone;
Expand Down
47 changes: 28 additions & 19 deletions lib/llvm-backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,38 +38,47 @@ impl Compiler for LLVMCompiler {
let (info, code_reader) = read_info::read_module(wasm, compiler_config).unwrap();
let (module, intrinsics) = code::parse_function_bodies(&info, code_reader).unwrap();

let backend = backend::LLVMBackend::new(module, intrinsics);
let (backend, cache_gen) = backend::LLVMBackend::new(module, intrinsics);

// Create placeholder values here.
let cache_gen = {
use wasmer_runtime_core::backend::{sys::Memory, CacheGen};
use wasmer_runtime_core::cache::Error as CacheError;
use wasmer_runtime_core::module::ModuleInfo;
// let cache_gen = {
// use wasmer_runtime_core::backend::{sys::Memory, CacheGen};
// use wasmer_runtime_core::cache::Error as CacheError;
// use wasmer_runtime_core::module::ModuleInfo;

struct Placeholder;
// struct Placeholder;

impl CacheGen for Placeholder {
fn generate_cache(
&self,
_module: &ModuleInner,
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), CacheError> {
unimplemented!()
}
}
// impl CacheGen for Placeholder {
// fn generate_cache(
// &self,
// _module: &ModuleInner,
// ) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), CacheError> {
// unimplemented!()
// }
// }

Box::new(Placeholder)
};
// Box::new(Placeholder)
// };

Ok(ModuleInner {
runnable_module: Box::new(backend),
cache_gen,
cache_gen: Box::new(cache_gen),

info,
})
}

unsafe fn from_cache(&self, _artifact: Artifact, _: Token) -> Result<ModuleInner, CacheError> {
unimplemented!("the llvm backend doesn't support caching yet")
unsafe fn from_cache(&self, artifact: Artifact, _: Token) -> Result<ModuleInner, CacheError> {
let (info, _, memory) = artifact.consume();
let (backend, cache_gen) =
backend::LLVMBackend::from_buffer(memory).map_err(CacheError::DeserializeError)?;

Ok(ModuleInner {
runnable_module: Box::new(backend),
cache_gen: Box::new(cache_gen),

info,
})
}
}

Expand Down
5 changes: 1 addition & 4 deletions lib/runtime-core/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,5 @@ pub trait RunnableModule: Send + Sync {
}

pub trait CacheGen: Send + Sync {
fn generate_cache(
&self,
module: &ModuleInner,
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), CacheError>;
fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), CacheError>;
}
8 changes: 6 additions & 2 deletions lib/runtime-core/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,12 @@ impl Module {
}

pub fn cache(&self) -> Result<Artifact, CacheError> {
let (info, backend_metadata, code) = self.inner.cache_gen.generate_cache(&self.inner)?;
Ok(Artifact::from_parts(info, backend_metadata, code))
let (backend_metadata, code) = self.inner.cache_gen.generate_cache()?;
Ok(Artifact::from_parts(
Box::new(self.inner.info.clone()),
backend_metadata,
code,
))
}

pub fn info(&self) -> &ModuleInfo {
Expand Down
2 changes: 0 additions & 2 deletions lib/runtime/examples/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ static WAT: &'static str = r#"
(type (;0;) (func (result i32)))
(import "env" "do_panic" (func $do_panic (type 0)))
(func $dbz (result i32)
call $do_panic
drop
i32.const 42
i32.const 0
i32.div_u
Expand Down
5 changes: 1 addition & 4 deletions lib/singlepass-backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,7 @@ use wasmer_runtime_core::{

struct Placeholder;
impl CacheGen for Placeholder {
fn generate_cache(
&self,
_module: &ModuleInner,
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), CacheError> {
fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), CacheError> {
Err(CacheError::Unknown(
"the singlepass backend doesn't support caching yet".to_string(),
))
Expand Down