mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-20 12:16:30 +00:00
Add caching support to llvm backend
This commit is contained in:
@ -27,18 +27,12 @@ impl CacheGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CacheGen for CacheGenerator {
|
impl CacheGen for CacheGenerator {
|
||||||
fn generate_cache(
|
fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), Error> {
|
||||||
&self,
|
|
||||||
module: &ModuleInner,
|
|
||||||
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), Error> {
|
|
||||||
let info = Box::new(module.info.clone());
|
|
||||||
|
|
||||||
// Clone the memory to a new location. This could take a long time,
|
// Clone the memory to a new location. This could take a long time,
|
||||||
// depending on the throughput of your memcpy implementation.
|
// depending on the throughput of your memcpy implementation.
|
||||||
let compiled_code = (*self.memory).clone();
|
let compiled_code = (*self.memory).clone();
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
info,
|
|
||||||
self.backend_cache.into_backend_data()?.into_boxed_slice(),
|
self.backend_cache.into_backend_data()?.into_boxed_slice(),
|
||||||
compiled_code,
|
compiled_code,
|
||||||
))
|
))
|
||||||
|
@ -175,21 +175,26 @@ WasmModule::WasmModule(
|
|||||||
callbacks_t callbacks
|
callbacks_t callbacks
|
||||||
) : memory_manager(std::unique_ptr<MemoryManager>(new MemoryManager(callbacks)))
|
) : memory_manager(std::unique_ptr<MemoryManager>(new MemoryManager(callbacks)))
|
||||||
{
|
{
|
||||||
object_file = llvm::cantFail(llvm::object::ObjectFile::createObjectFile(llvm::MemoryBufferRef(
|
|
||||||
|
|
||||||
|
if (auto created_object_file = llvm::object::ObjectFile::createObjectFile(llvm::MemoryBufferRef(
|
||||||
llvm::StringRef((const char *)object_start, object_size), "object"
|
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));
|
||||||
|
|
||||||
SymbolLookup symbol_resolver(callbacks);
|
runtime_dyld->setProcessAllSections(true);
|
||||||
runtime_dyld = std::unique_ptr<llvm::RuntimeDyld>(new llvm::RuntimeDyld(*memory_manager, symbol_resolver));
|
|
||||||
|
|
||||||
runtime_dyld->setProcessAllSections(true);
|
runtime_dyld->loadObject(*object_file);
|
||||||
|
runtime_dyld->finalizeWithMemoryManagerLocking();
|
||||||
|
|
||||||
runtime_dyld->loadObject(*object_file);
|
if (runtime_dyld->hasError()) {
|
||||||
runtime_dyld->finalizeWithMemoryManagerLocking();
|
_init_failed = true;
|
||||||
|
return;
|
||||||
if (runtime_dyld->hasError()) {
|
}
|
||||||
std::cout << "RuntimeDyld error: " << (std::string)runtime_dyld->getErrorString() << std::endl;
|
} else {
|
||||||
abort();
|
_init_failed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,6 +152,7 @@ struct WasmModule
|
|||||||
|
|
||||||
void *get_func(llvm::StringRef name) const;
|
void *get_func(llvm::StringRef name) const;
|
||||||
|
|
||||||
|
bool _init_failed = false;
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<llvm::RuntimeDyld::MemoryManager> memory_manager;
|
std::unique_ptr<llvm::RuntimeDyld::MemoryManager> memory_manager;
|
||||||
std::unique_ptr<llvm::object::ObjectFile> object_file;
|
std::unique_ptr<llvm::object::ObjectFile> object_file;
|
||||||
@ -164,6 +165,10 @@ extern "C"
|
|||||||
{
|
{
|
||||||
*module_out = new WasmModule(mem_ptr, mem_size, callbacks);
|
*module_out = new WasmModule(mem_ptr, mem_size, callbacks);
|
||||||
|
|
||||||
|
if ((*module_out)->_init_failed) {
|
||||||
|
return RESULT_OBJECT_LOAD_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
return RESULT_OK;
|
return RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,12 +13,17 @@ use std::{
|
|||||||
any::Any,
|
any::Any,
|
||||||
ffi::{c_void, CString},
|
ffi::{c_void, CString},
|
||||||
mem,
|
mem,
|
||||||
|
ops::Deref,
|
||||||
ptr::{self, NonNull},
|
ptr::{self, NonNull},
|
||||||
slice, str,
|
slice, str,
|
||||||
sync::Once,
|
sync::{Arc, Once},
|
||||||
};
|
};
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
backend::RunnableModule,
|
backend::{
|
||||||
|
sys::{Memory, Protect},
|
||||||
|
CacheGen, RunnableModule,
|
||||||
|
},
|
||||||
|
cache::Error as CacheError,
|
||||||
module::ModuleInfo,
|
module::ModuleInfo,
|
||||||
structures::TypedIndex,
|
structures::TypedIndex,
|
||||||
typed_func::{Wasm, WasmTrapInfo},
|
typed_func::{Wasm, WasmTrapInfo},
|
||||||
@ -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 Send for LLVMBackend {}
|
||||||
unsafe impl Sync for LLVMBackend {}
|
unsafe impl Sync for LLVMBackend {}
|
||||||
|
|
||||||
pub struct LLVMBackend {
|
pub struct LLVMBackend {
|
||||||
module: *mut LLVMModule,
|
module: *mut LLVMModule,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
memory_buffer: MemoryBuffer,
|
buffer: Arc<Buffer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LLVMBackend {
|
impl LLVMBackend {
|
||||||
pub fn new(module: Module, _intrinsics: Intrinsics) -> Self {
|
pub fn new(module: Module, _intrinsics: Intrinsics) -> (Self, LLVMCache) {
|
||||||
Target::initialize_x86(&InitializationConfig {
|
Target::initialize_x86(&InitializationConfig {
|
||||||
asm_parser: true,
|
asm_parser: true,
|
||||||
asm_printer: true,
|
asm_printer: true,
|
||||||
@ -262,10 +282,44 @@ impl LLVMBackend {
|
|||||||
panic!("failed to load object")
|
panic!("failed to load object")
|
||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
let buffer = Arc::new(Buffer::LlvmMemory(memory_buffer));
|
||||||
module,
|
|
||||||
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 },
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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")]
|
#[cfg(feature = "disasm")]
|
||||||
unsafe fn disass_ptr(ptr: *const u8, size: usize, inst_count: usize) {
|
unsafe fn disass_ptr(ptr: *const u8, size: usize, inst_count: usize) {
|
||||||
use capstone::arch::BuildsCapstone;
|
use capstone::arch::BuildsCapstone;
|
||||||
|
@ -38,38 +38,47 @@ impl Compiler for LLVMCompiler {
|
|||||||
let (info, code_reader) = read_info::read_module(wasm, compiler_config).unwrap();
|
let (info, code_reader) = read_info::read_module(wasm, compiler_config).unwrap();
|
||||||
let (module, intrinsics) = code::parse_function_bodies(&info, code_reader).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.
|
// Create placeholder values here.
|
||||||
let cache_gen = {
|
// let cache_gen = {
|
||||||
use wasmer_runtime_core::backend::{sys::Memory, CacheGen};
|
// use wasmer_runtime_core::backend::{sys::Memory, CacheGen};
|
||||||
use wasmer_runtime_core::cache::Error as CacheError;
|
// use wasmer_runtime_core::cache::Error as CacheError;
|
||||||
use wasmer_runtime_core::module::ModuleInfo;
|
// use wasmer_runtime_core::module::ModuleInfo;
|
||||||
|
|
||||||
struct Placeholder;
|
// struct Placeholder;
|
||||||
|
|
||||||
impl CacheGen for Placeholder {
|
// impl CacheGen for Placeholder {
|
||||||
fn generate_cache(
|
// fn generate_cache(
|
||||||
&self,
|
// &self,
|
||||||
_module: &ModuleInner,
|
// _module: &ModuleInner,
|
||||||
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), CacheError> {
|
// ) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), CacheError> {
|
||||||
unimplemented!()
|
// unimplemented!()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
Box::new(Placeholder)
|
// Box::new(Placeholder)
|
||||||
};
|
// };
|
||||||
|
|
||||||
Ok(ModuleInner {
|
Ok(ModuleInner {
|
||||||
runnable_module: Box::new(backend),
|
runnable_module: Box::new(backend),
|
||||||
cache_gen,
|
cache_gen: Box::new(cache_gen),
|
||||||
|
|
||||||
info,
|
info,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn from_cache(&self, _artifact: Artifact, _: Token) -> Result<ModuleInner, CacheError> {
|
unsafe fn from_cache(&self, artifact: Artifact, _: Token) -> Result<ModuleInner, CacheError> {
|
||||||
unimplemented!("the llvm backend doesn't support caching yet")
|
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,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,8 +83,5 @@ pub trait RunnableModule: Send + Sync {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait CacheGen: Send + Sync {
|
pub trait CacheGen: Send + Sync {
|
||||||
fn generate_cache(
|
fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), CacheError>;
|
||||||
&self,
|
|
||||||
module: &ModuleInner,
|
|
||||||
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), CacheError>;
|
|
||||||
}
|
}
|
||||||
|
@ -121,8 +121,12 @@ impl Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn cache(&self) -> Result<Artifact, CacheError> {
|
pub fn cache(&self) -> Result<Artifact, CacheError> {
|
||||||
let (info, backend_metadata, code) = self.inner.cache_gen.generate_cache(&self.inner)?;
|
let (backend_metadata, code) = self.inner.cache_gen.generate_cache()?;
|
||||||
Ok(Artifact::from_parts(info, backend_metadata, code))
|
Ok(Artifact::from_parts(
|
||||||
|
Box::new(self.inner.info.clone()),
|
||||||
|
backend_metadata,
|
||||||
|
code,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn info(&self) -> &ModuleInfo {
|
pub fn info(&self) -> &ModuleInfo {
|
||||||
|
@ -7,8 +7,6 @@ static WAT: &'static str = r#"
|
|||||||
(type (;0;) (func (result i32)))
|
(type (;0;) (func (result i32)))
|
||||||
(import "env" "do_panic" (func $do_panic (type 0)))
|
(import "env" "do_panic" (func $do_panic (type 0)))
|
||||||
(func $dbz (result i32)
|
(func $dbz (result i32)
|
||||||
call $do_panic
|
|
||||||
drop
|
|
||||||
i32.const 42
|
i32.const 42
|
||||||
i32.const 0
|
i32.const 0
|
||||||
i32.div_u
|
i32.div_u
|
||||||
|
@ -36,10 +36,7 @@ use wasmer_runtime_core::{
|
|||||||
|
|
||||||
struct Placeholder;
|
struct Placeholder;
|
||||||
impl CacheGen for Placeholder {
|
impl CacheGen for Placeholder {
|
||||||
fn generate_cache(
|
fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), CacheError> {
|
||||||
&self,
|
|
||||||
_module: &ModuleInner,
|
|
||||||
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), CacheError> {
|
|
||||||
Err(CacheError::Unknown(
|
Err(CacheError::Unknown(
|
||||||
"the singlepass backend doesn't support caching yet".to_string(),
|
"the singlepass backend doesn't support caching yet".to_string(),
|
||||||
))
|
))
|
||||||
|
Reference in New Issue
Block a user