Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support declaring anonymous functions and data objects #2750

Merged
merged 1 commit into from
Apr 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -488,40 +535,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 @@ -534,25 +566,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