Add SimpleJIT internal symbol table.
Allows for host programs to directly expose symbols to jitted code without needing to deal with platform-specific linker arguments, or dynamic dispatch.
This commit is contained in:
@@ -10,6 +10,7 @@ use cranelift_module::{
|
|||||||
use cranelift_native;
|
use cranelift_native;
|
||||||
use libc;
|
use libc;
|
||||||
use memory::Memory;
|
use memory::Memory;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use target_lexicon::PointerWidth;
|
use target_lexicon::PointerWidth;
|
||||||
@@ -19,6 +20,7 @@ use winapi;
|
|||||||
/// A builder for `SimpleJITBackend`.
|
/// A builder for `SimpleJITBackend`.
|
||||||
pub struct SimpleJITBuilder {
|
pub struct SimpleJITBuilder {
|
||||||
isa: Box<TargetIsa>,
|
isa: Box<TargetIsa>,
|
||||||
|
symbols: HashMap<String, *const u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SimpleJITBuilder {
|
impl SimpleJITBuilder {
|
||||||
@@ -40,7 +42,44 @@ impl SimpleJITBuilder {
|
|||||||
/// instead.
|
/// instead.
|
||||||
pub fn with_isa(isa: Box<TargetIsa>) -> Self {
|
pub fn with_isa(isa: Box<TargetIsa>) -> Self {
|
||||||
debug_assert!(!isa.flags().is_pic(), "SimpleJIT requires non-PIC code");
|
debug_assert!(!isa.flags().is_pic(), "SimpleJIT requires non-PIC code");
|
||||||
Self { isa }
|
let symbols = HashMap::new();
|
||||||
|
Self { isa, symbols }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Define a symbol in the internal symbol table.
|
||||||
|
///
|
||||||
|
/// The JIT will use the symbol table to resolve names that are declared,
|
||||||
|
/// but not defined, in the module being compiled. A common example is
|
||||||
|
/// external functions. With this method, functions and data can be exposed
|
||||||
|
/// to the code being compiled which are defined by the host.
|
||||||
|
///
|
||||||
|
/// If a symbol is defined more than once, the most recent definition will
|
||||||
|
/// be retained.
|
||||||
|
///
|
||||||
|
/// If the JIT fails to find a symbol in its internal table, it will fall
|
||||||
|
/// back to a platform-specific search (this typically involves searching
|
||||||
|
/// the current process for public symbols, followed by searching the
|
||||||
|
/// platform's C runtime).
|
||||||
|
pub fn symbol<'a, K>(&'a mut self, name: K, ptr: *const u8) -> &'a mut Self
|
||||||
|
where
|
||||||
|
K: Into<String>,
|
||||||
|
{
|
||||||
|
self.symbols.insert(name.into(), ptr);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Define multiple symbols in the internal symbol table.
|
||||||
|
///
|
||||||
|
/// Using this is equivalent to calling `symbol` on each element.
|
||||||
|
pub fn symbols<'a, It, K>(&'a mut self, symbols: It) -> &'a mut Self
|
||||||
|
where
|
||||||
|
It: IntoIterator<Item = (K, *const u8)>,
|
||||||
|
K: Into<String>,
|
||||||
|
{
|
||||||
|
for (name, ptr) in symbols {
|
||||||
|
self.symbols.insert(name.into(), ptr);
|
||||||
|
}
|
||||||
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,6 +87,7 @@ impl SimpleJITBuilder {
|
|||||||
/// directly called and accessed.
|
/// directly called and accessed.
|
||||||
pub struct SimpleJITBackend {
|
pub struct SimpleJITBackend {
|
||||||
isa: Box<TargetIsa>,
|
isa: Box<TargetIsa>,
|
||||||
|
symbols: HashMap<String, *const u8>,
|
||||||
code_memory: Memory,
|
code_memory: Memory,
|
||||||
readonly_memory: Memory,
|
readonly_memory: Memory,
|
||||||
writable_memory: Memory,
|
writable_memory: Memory,
|
||||||
@@ -73,6 +113,15 @@ pub struct SimpleJITCompiledData {
|
|||||||
relocs: Vec<RelocRecord>,
|
relocs: Vec<RelocRecord>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SimpleJITBackend {
|
||||||
|
fn lookup_symbol(&self, name: &str) -> *const u8 {
|
||||||
|
match self.symbols.get(name) {
|
||||||
|
Some(&ptr) => ptr,
|
||||||
|
None => lookup_with_dlsym(name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'simple_jit_backend> Backend for SimpleJITBackend {
|
impl<'simple_jit_backend> Backend for SimpleJITBackend {
|
||||||
type Builder = SimpleJITBuilder;
|
type Builder = SimpleJITBuilder;
|
||||||
|
|
||||||
@@ -96,6 +145,7 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend {
|
|||||||
fn new(builder: SimpleJITBuilder) -> Self {
|
fn new(builder: SimpleJITBuilder) -> Self {
|
||||||
Self {
|
Self {
|
||||||
isa: builder.isa,
|
isa: builder.isa,
|
||||||
|
symbols: builder.symbols,
|
||||||
code_memory: Memory::new(),
|
code_memory: Memory::new(),
|
||||||
readonly_memory: Memory::new(),
|
readonly_memory: Memory::new(),
|
||||||
writable_memory: Memory::new(),
|
writable_memory: Memory::new(),
|
||||||
@@ -249,13 +299,13 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend {
|
|||||||
let (def, name_str, _signature) = namespace.get_function_definition(&name);
|
let (def, name_str, _signature) = namespace.get_function_definition(&name);
|
||||||
match def {
|
match def {
|
||||||
Some(compiled) => compiled.code,
|
Some(compiled) => compiled.code,
|
||||||
None => lookup_with_dlsym(name_str),
|
None => self.lookup_symbol(name_str),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let (def, name_str, _writable) = namespace.get_data_definition(&name);
|
let (def, name_str, _writable) = namespace.get_data_definition(&name);
|
||||||
match def {
|
match def {
|
||||||
Some(compiled) => compiled.storage,
|
Some(compiled) => compiled.storage,
|
||||||
None => lookup_with_dlsym(name_str),
|
None => self.lookup_symbol(name_str),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// TODO: Handle overflow.
|
// TODO: Handle overflow.
|
||||||
@@ -314,13 +364,13 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend {
|
|||||||
let (def, name_str, _signature) = namespace.get_function_definition(&name);
|
let (def, name_str, _signature) = namespace.get_function_definition(&name);
|
||||||
match def {
|
match def {
|
||||||
Some(compiled) => compiled.code,
|
Some(compiled) => compiled.code,
|
||||||
None => lookup_with_dlsym(name_str),
|
None => self.lookup_symbol(name_str),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let (def, name_str, _writable) = namespace.get_data_definition(&name);
|
let (def, name_str, _writable) = namespace.get_data_definition(&name);
|
||||||
match def {
|
match def {
|
||||||
Some(compiled) => compiled.storage,
|
Some(compiled) => compiled.storage,
|
||||||
None => lookup_with_dlsym(name_str),
|
None => self.lookup_symbol(name_str),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// TODO: Handle overflow.
|
// TODO: Handle overflow.
|
||||||
|
|||||||
Reference in New Issue
Block a user