Skip to content

Commit

Permalink
Merge #367
Browse files Browse the repository at this point in the history
367: Add caching support to llvm backend r=lachlansneff a=lachlansneff

This changes the `CacheGen` trait a little, since it was weird.

Co-authored-by: Lachlan Sneff <lachlan.sneff@gmail.com>
  • Loading branch information
bors[bot] and lachlansneff committed Apr 19, 2019
2 parents ed65105 + c3ef1f8 commit 88e374d
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 60 deletions.
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
35 changes: 12 additions & 23 deletions lib/llvm-backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,39 +38,28 @@ 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;

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

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

Box::new(Placeholder)
};
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,
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")
}
}

fn validate(bytes: &[u8]) -> Result<(), CompileError> {
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

0 comments on commit 88e374d

Please sign in to comment.