Add a way to define a symbol lookup fn for the JIT (#2745)

* Couple of cranelift-jit cleanups

* Add a way to define a symbol lookup fn for the JIT
This commit is contained in:
bjorn3
2022-02-19 17:33:39 +01:00
committed by GitHub
parent 5ff1ddee5b
commit 2ca01ae947

View File

@@ -14,6 +14,7 @@ use cranelift_module::{
ModuleDeclarations, ModuleError, ModuleResult, ModuleDeclarations, ModuleError, ModuleResult,
}; };
use log::info; use log::info;
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::{TryFrom, TryInto}; use std::convert::{TryFrom, TryInto};
use std::ffi::CString; use std::ffi::CString;
@@ -31,6 +32,7 @@ const READONLY_DATA_ALIGNMENT: u64 = 0x1;
pub struct JITBuilder { pub struct JITBuilder {
isa: Box<dyn TargetIsa>, isa: Box<dyn TargetIsa>,
symbols: HashMap<String, *const u8>, symbols: HashMap<String, *const u8>,
lookup_symbols: Vec<Box<dyn Fn(&str) -> Option<*const u8>>>,
libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>, libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>,
hotswap_enabled: bool, hotswap_enabled: bool,
} }
@@ -73,9 +75,11 @@ impl JITBuilder {
libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>, libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>,
) -> Self { ) -> Self {
let symbols = HashMap::new(); let symbols = HashMap::new();
let lookup_symbols = vec![Box::new(lookup_with_dlsym) as Box<_>];
Self { Self {
isa, isa,
symbols, symbols,
lookup_symbols,
libcall_names, libcall_names,
hotswap_enabled: false, hotswap_enabled: false,
} }
@@ -95,7 +99,7 @@ impl JITBuilder {
/// back to a platform-specific search (this typically involves searching /// back to a platform-specific search (this typically involves searching
/// the current process for public symbols, followed by searching the /// the current process for public symbols, followed by searching the
/// platform's C runtime). /// platform's C runtime).
pub fn symbol<K>(&mut self, name: K, ptr: *const u8) -> &Self pub fn symbol<K>(&mut self, name: K, ptr: *const u8) -> &mut Self
where where
K: Into<String>, K: Into<String>,
{ {
@@ -106,7 +110,7 @@ impl JITBuilder {
/// Define multiple symbols in the internal symbol table. /// Define multiple symbols in the internal symbol table.
/// ///
/// Using this is equivalent to calling `symbol` on each element. /// Using this is equivalent to calling `symbol` on each element.
pub fn symbols<It, K>(&mut self, symbols: It) -> &Self pub fn symbols<It, K>(&mut self, symbols: It) -> &mut Self
where where
It: IntoIterator<Item = (K, *const u8)>, It: IntoIterator<Item = (K, *const u8)>,
K: Into<String>, K: Into<String>,
@@ -117,6 +121,18 @@ impl JITBuilder {
self self
} }
/// Add a symbol lookup fn.
///
/// Symbol lookup fn's are used to lookup symbols when they couldn't be found in the internal
/// symbol table. Symbol lookup fn's are called in reverse of the order in which they were added.
pub fn symbol_lookup_fn(
&mut self,
symbol_lookup_fn: Box<dyn Fn(&str) -> Option<*const u8>>,
) -> &mut Self {
self.lookup_symbols.push(symbol_lookup_fn);
self
}
/// Enable or disable hotswap support. See [`JITModule::prepare_for_function_redefine`] /// Enable or disable hotswap support. See [`JITModule::prepare_for_function_redefine`]
/// for more information. /// for more information.
/// ///
@@ -143,7 +159,8 @@ struct GotUpdate {
pub struct JITModule { pub struct JITModule {
isa: Box<dyn TargetIsa>, isa: Box<dyn TargetIsa>,
hotswap_enabled: bool, hotswap_enabled: bool,
symbols: HashMap<String, *const u8>, symbols: RefCell<HashMap<String, *const u8>>,
lookup_symbols: Vec<Box<dyn Fn(&str) -> Option<*const u8>>>,
libcall_names: Box<dyn Fn(ir::LibCall) -> String>, libcall_names: Box<dyn Fn(ir::LibCall) -> String>,
memory: MemoryHandle, memory: MemoryHandle,
declarations: ModuleDeclarations, declarations: ModuleDeclarations,
@@ -184,10 +201,20 @@ impl JITModule {
} }
fn lookup_symbol(&self, name: &str) -> Option<*const u8> { fn lookup_symbol(&self, name: &str) -> Option<*const u8> {
self.symbols match self.symbols.borrow_mut().entry(name.to_owned()) {
.get(name) std::collections::hash_map::Entry::Occupied(occ) => Some(*occ.get()),
.copied() std::collections::hash_map::Entry::Vacant(vac) => {
.or_else(|| lookup_with_dlsym(name)) let ptr = self
.lookup_symbols
.iter()
.rev() // Try last lookup function first
.find_map(|lookup| lookup(name));
if let Some(ptr) = ptr {
vac.insert(ptr);
}
ptr
}
}
} }
fn new_got_entry(&mut self, val: *const u8) -> NonNull<AtomicPtr<u8>> { fn new_got_entry(&mut self, val: *const u8) -> NonNull<AtomicPtr<u8>> {
@@ -277,7 +304,7 @@ impl JITModule {
} }
} }
}; };
if let Some(ptr) = self.lookup_symbol(&name) { if let Some(ptr) = self.lookup_symbol(name) {
ptr ptr
} else if linkage == Linkage::Preemptible { } else if linkage == Linkage::Preemptible {
0 as *const u8 0 as *const u8
@@ -455,7 +482,8 @@ impl JITModule {
let mut module = Self { let mut module = Self {
isa: builder.isa, isa: builder.isa,
hotswap_enabled: builder.hotswap_enabled, hotswap_enabled: builder.hotswap_enabled,
symbols: builder.symbols, symbols: RefCell::new(builder.symbols),
lookup_symbols: builder.lookup_symbols,
libcall_names: builder.libcall_names, libcall_names: builder.libcall_names,
memory: MemoryHandle { memory: MemoryHandle {
code: Memory::new(), code: Memory::new(),
@@ -483,12 +511,7 @@ impl JITModule {
}; };
for &libcall in all_libcalls { for &libcall in all_libcalls {
let sym = (module.libcall_names)(libcall); let sym = (module.libcall_names)(libcall);
let addr = if let Some(addr) = module let addr = if let Some(addr) = module.lookup_symbol(&sym) {
.symbols
.get(&sym)
.copied()
.or_else(|| lookup_with_dlsym(&sym))
{
addr addr
} else { } else {
continue; continue;