Skip to content

Commit

Permalink
Merge pull request #2750 from bjorn3/anon_allocs
Browse files Browse the repository at this point in the history
Support declaring anonymous functions and data objects
  • Loading branch information
cfallin authored Apr 12, 2021
2 parents 2a32567 + cc89111 commit 67cc42d
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 56 deletions.
123 changes: 78 additions & 45 deletions cranelift/jit/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,53 @@ impl JITModule {
.or_else(|| lookup_with_dlsym(name))
}

fn new_func_plt_entry(&mut self, id: FuncId, val: *const u8) {
let got_entry = self
.memory
.writable
.allocate(
std::mem::size_of::<*const u8>(),
std::mem::align_of::<*const u8>().try_into().unwrap(),
)
.unwrap()
.cast::<*const u8>();
self.function_got_entries[id] = Some(NonNull::new(got_entry).unwrap());
unsafe {
std::ptr::write(got_entry, val);
}
let plt_entry = self
.memory
.code
.allocate(std::mem::size_of::<[u8; 16]>(), EXECUTABLE_DATA_ALIGNMENT)
.unwrap()
.cast::<[u8; 16]>();
self.record_function_for_perf(
plt_entry as *mut _,
std::mem::size_of::<[u8; 16]>(),
&format!("{}@plt", self.declarations.get_function_decl(id).name),
);
self.function_plt_entries[id] = Some(NonNull::new(plt_entry).unwrap());
unsafe {
Self::write_plt_entry_bytes(plt_entry, got_entry);
}
}

fn new_data_got_entry(&mut self, id: DataId, val: *const u8) {
let got_entry = self
.memory
.writable
.allocate(
std::mem::size_of::<*const u8>(),
std::mem::align_of::<*const u8>().try_into().unwrap(),
)
.unwrap()
.cast::<*const u8>();
self.data_object_got_entries[id] = Some(NonNull::new(got_entry).unwrap());
unsafe {
std::ptr::write(got_entry, val);
}
}

unsafe fn write_plt_entry_bytes(plt_ptr: *mut [u8; 16], got_ptr: *mut *const u8) {
assert!(
cfg!(target_arch = "x86_64"),
Expand Down Expand Up @@ -494,40 +541,25 @@ impl Module for JITModule {
linkage: Linkage,
signature: &ir::Signature,
) -> ModuleResult<FuncId> {
let (id, _decl) = self
let (id, linkage) = self
.declarations
.declare_function(name, linkage, signature)?;
if self.function_got_entries[id].is_none() && self.isa.flags().is_pic() {
let got_entry = self
.memory
.writable
.allocate(
std::mem::size_of::<*const u8>(),
std::mem::align_of::<*const u8>().try_into().unwrap(),
)
.unwrap()
.cast::<*const u8>();
self.function_got_entries[id] = Some(NonNull::new(got_entry).unwrap());
// FIXME populate got entries with a null pointer when defined
let val = self.lookup_symbol(name).unwrap_or(std::ptr::null());
unsafe {
std::ptr::write(got_entry, val);
}
let plt_entry = self
.memory
.code
.allocate(std::mem::size_of::<[u8; 16]>(), EXECUTABLE_DATA_ALIGNMENT)
.unwrap()
.cast::<[u8; 16]>();
self.record_function_for_perf(
plt_entry as *mut _,
std::mem::size_of::<[u8; 16]>(),
&format!("{}@plt", name),
);
self.function_plt_entries[id] = Some(NonNull::new(plt_entry).unwrap());
unsafe {
Self::write_plt_entry_bytes(plt_entry, got_entry);
}
let val = if linkage == Linkage::Import {
self.lookup_symbol(name).unwrap_or(std::ptr::null())
} else {
std::ptr::null()
};
self.new_func_plt_entry(id, val);
}
Ok(id)
}

fn declare_anonymous_function(&mut self, signature: &ir::Signature) -> ModuleResult<FuncId> {
let id = self.declarations.declare_anonymous_function(signature)?;
if self.isa.flags().is_pic() {
self.new_func_plt_entry(id, std::ptr::null());
}
Ok(id)
}
Expand All @@ -540,25 +572,26 @@ impl Module for JITModule {
tls: bool,
) -> ModuleResult<DataId> {
assert!(!tls, "JIT doesn't yet support TLS");
let (id, _decl) = self
let (id, linkage) = self
.declarations
.declare_data(name, linkage, writable, tls)?;
if self.data_object_got_entries[id].is_none() && self.isa.flags().is_pic() {
let got_entry = self
.memory
.writable
.allocate(
std::mem::size_of::<*const u8>(),
std::mem::align_of::<*const u8>().try_into().unwrap(),
)
.unwrap()
.cast::<*const u8>();
self.data_object_got_entries[id] = Some(NonNull::new(got_entry).unwrap());
// FIXME populate got entries with a null pointer when defined
let val = self.lookup_symbol(name).unwrap_or(std::ptr::null());
unsafe {
std::ptr::write(got_entry, val);
}
let val = if linkage == Linkage::Import {
self.lookup_symbol(name).unwrap_or(std::ptr::null())
} else {
std::ptr::null()
};
self.new_data_got_entry(id, val);
}
Ok(id)
}

fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId> {
assert!(!tls, "JIT doesn't yet support TLS");
let id = self.declarations.declare_anonymous_data(writable, tls)?;
if self.isa.flags().is_pic() {
self.new_data_got_entry(id, std::ptr::null());
}
Ok(id)
}
Expand Down
52 changes: 46 additions & 6 deletions cranelift/module/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,15 +268,15 @@ impl ModuleDeclarations {
name: &str,
linkage: Linkage,
signature: &ir::Signature,
) -> ModuleResult<(FuncId, &FunctionDeclaration)> {
) -> ModuleResult<(FuncId, Linkage)> {
// TODO: Can we avoid allocating names so often?
use super::hash_map::Entry::*;
match self.names.entry(name.to_owned()) {
Occupied(entry) => match *entry.get() {
FuncOrDataId::Func(id) => {
let existing = &mut self.functions[id];
existing.merge(linkage, signature)?;
Ok((id, existing))
Ok((id, existing.linkage))
}
FuncOrDataId::Data(..) => {
Err(ModuleError::IncompatibleDeclaration(name.to_owned()))
Expand All @@ -289,27 +289,41 @@ impl ModuleDeclarations {
signature: signature.clone(),
});
entry.insert(FuncOrDataId::Func(id));
Ok((id, &self.functions[id]))
Ok((id, self.functions[id].linkage))
}
}
}

/// Declare an anonymous function in this module.
pub fn declare_anonymous_function(
&mut self,
signature: &ir::Signature,
) -> ModuleResult<FuncId> {
let id = self.functions.push(FunctionDeclaration {
name: String::new(),
linkage: Linkage::Local,
signature: signature.clone(),
});
self.functions[id].name = format!(".L{:?}", id);
Ok(id)
}

/// Declare a data object in this module.
pub fn declare_data(
&mut self,
name: &str,
linkage: Linkage,
writable: bool,
tls: bool,
) -> ModuleResult<(DataId, &DataDeclaration)> {
) -> ModuleResult<(DataId, Linkage)> {
// TODO: Can we avoid allocating names so often?
use super::hash_map::Entry::*;
match self.names.entry(name.to_owned()) {
Occupied(entry) => match *entry.get() {
FuncOrDataId::Data(id) => {
let existing = &mut self.data_objects[id];
existing.merge(linkage, writable, tls);
Ok((id, existing))
Ok((id, existing.linkage))
}

FuncOrDataId::Func(..) => {
Expand All @@ -324,10 +338,22 @@ impl ModuleDeclarations {
tls,
});
entry.insert(FuncOrDataId::Data(id));
Ok((id, &self.data_objects[id]))
Ok((id, self.data_objects[id].linkage))
}
}
}

/// Declare an anonymous data object in this module.
pub fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId> {
let id = self.data_objects.push(DataDeclaration {
name: String::new(),
linkage: Linkage::Local,
writable,
tls,
});
self.data_objects[id].name = format!(".L{:?}", id);
Ok(id)
}
}

/// Information about the compiled function.
Expand Down Expand Up @@ -411,6 +437,9 @@ pub trait Module {
signature: &ir::Signature,
) -> ModuleResult<FuncId>;

/// Declare an anonymous function in this module.
fn declare_anonymous_function(&mut self, signature: &ir::Signature) -> ModuleResult<FuncId>;

/// Declare a data object in this module.
fn declare_data(
&mut self,
Expand All @@ -420,6 +449,9 @@ pub trait Module {
tls: bool,
) -> ModuleResult<DataId>;

/// Declare an anonymous data object in this module.
fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId>;

/// Use this when you're building the IR of a function to reference a function.
///
/// TODO: Coalesce redundant decls and signatures.
Expand Down Expand Up @@ -532,6 +564,10 @@ impl<M: Module> Module for &mut M {
(**self).declare_function(name, linkage, signature)
}

fn declare_anonymous_function(&mut self, signature: &ir::Signature) -> ModuleResult<FuncId> {
(**self).declare_anonymous_function(signature)
}

fn declare_data(
&mut self,
name: &str,
Expand All @@ -542,6 +578,10 @@ impl<M: Module> Module for &mut M {
(**self).declare_data(name, linkage, writable, tls)
}

fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId> {
(**self).declare_anonymous_data(writable, tls)
}

fn declare_func_in_func(&self, func: FuncId, in_func: &mut ir::Function) -> ir::FuncRef {
(**self).declare_func_in_func(func, in_func)
}
Expand Down
Loading

0 comments on commit 67cc42d

Please sign in to comment.