Allow serializing all cranelift-module data structures (#6172)
* Remove ModuleCompiledFunction The same information can be retrieved using ctx.compiled_code().unwrap().code_info().total_size In addition for Module implementations that don't immediately compile the given function there is no correct value that can be returned. * Don't give anonymous functions and data objects an internal name This internal name can conflict if a module is serialized and then deserialized into another module. It also wasn't used by any of the Module implementations anyway. * Allow serializing all cranelift-module data structures This allows a Module implementation to serialize it's internal state and deserialize it in another compilation session. For example to implement LTO or to load the module into cranelift-interpreter. * Use expect
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -747,6 +747,7 @@ dependencies = [
|
|||||||
"cranelift-codegen",
|
"cranelift-codegen",
|
||||||
"cranelift-control",
|
"cranelift-control",
|
||||||
"hashbrown 0.13.2",
|
"hashbrown 0.13.2",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ use super::{RelSourceLoc, SourceLoc, UserExternalName};
|
|||||||
|
|
||||||
/// A version marker used to ensure that serialized clif ir is never deserialized with a
|
/// A version marker used to ensure that serialized clif ir is never deserialized with a
|
||||||
/// different version of Cranelift.
|
/// different version of Cranelift.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Hash)]
|
#[derive(Default, Copy, Clone, Debug, PartialEq, Hash)]
|
||||||
pub struct VersionMarker;
|
pub struct VersionMarker;
|
||||||
|
|
||||||
#[cfg(feature = "enable-serde")]
|
#[cfg(feature = "enable-serde")]
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
//! Defines `JITModule`.
|
//! Defines `JITModule`.
|
||||||
|
|
||||||
use crate::{compiled_blob::CompiledBlob, memory::BranchProtection, memory::Memory};
|
use crate::{compiled_blob::CompiledBlob, memory::BranchProtection, memory::Memory};
|
||||||
|
use cranelift_codegen::binemit::Reloc;
|
||||||
use cranelift_codegen::isa::{OwnedTargetIsa, TargetIsa};
|
use cranelift_codegen::isa::{OwnedTargetIsa, TargetIsa};
|
||||||
use cranelift_codegen::settings::Configurable;
|
use cranelift_codegen::settings::Configurable;
|
||||||
use cranelift_codegen::{self, ir, settings, MachReloc};
|
use cranelift_codegen::{self, ir, settings, MachReloc};
|
||||||
use cranelift_codegen::{binemit::Reloc, CodegenError};
|
|
||||||
use cranelift_control::ControlPlane;
|
use cranelift_control::ControlPlane;
|
||||||
use cranelift_entity::SecondaryMap;
|
use cranelift_entity::SecondaryMap;
|
||||||
use cranelift_module::{
|
use cranelift_module::{
|
||||||
DataDescription, DataId, FuncId, Init, Linkage, Module, ModuleCompiledFunction,
|
DataDescription, DataId, FuncId, Init, Linkage, Module, ModuleDeclarations, ModuleError,
|
||||||
ModuleDeclarations, ModuleError, ModuleExtName, ModuleReloc, ModuleResult,
|
ModuleExtName, ModuleReloc, ModuleResult,
|
||||||
};
|
};
|
||||||
use log::info;
|
use log::info;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
@@ -272,7 +272,10 @@ impl JITModule {
|
|||||||
self.record_function_for_perf(
|
self.record_function_for_perf(
|
||||||
plt_entry.as_ptr().cast(),
|
plt_entry.as_ptr().cast(),
|
||||||
std::mem::size_of::<[u8; 16]>(),
|
std::mem::size_of::<[u8; 16]>(),
|
||||||
&format!("{}@plt", self.declarations.get_function_decl(id).name),
|
&format!(
|
||||||
|
"{}@plt",
|
||||||
|
self.declarations.get_function_decl(id).linkage_name(id)
|
||||||
|
),
|
||||||
);
|
);
|
||||||
self.function_plt_entries[id] = Some(plt_entry);
|
self.function_plt_entries[id] = Some(plt_entry);
|
||||||
}
|
}
|
||||||
@@ -323,6 +326,9 @@ impl JITModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let name = name
|
||||||
|
.as_ref()
|
||||||
|
.expect("anonymous symbol must be defined locally");
|
||||||
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 {
|
||||||
@@ -554,13 +560,15 @@ impl JITModule {
|
|||||||
assert!(self.hotswap_enabled, "Hotswap support is not enabled");
|
assert!(self.hotswap_enabled, "Hotswap support is not enabled");
|
||||||
let decl = self.declarations.get_function_decl(func_id);
|
let decl = self.declarations.get_function_decl(func_id);
|
||||||
if !decl.linkage.is_definable() {
|
if !decl.linkage.is_definable() {
|
||||||
return Err(ModuleError::InvalidImportDefinition(decl.name.clone()));
|
return Err(ModuleError::InvalidImportDefinition(
|
||||||
|
decl.linkage_name(func_id).into_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.compiled_functions[func_id].is_none() {
|
if self.compiled_functions[func_id].is_none() {
|
||||||
return Err(ModuleError::Backend(anyhow::anyhow!(
|
return Err(ModuleError::Backend(anyhow::anyhow!(
|
||||||
"Tried to redefine not yet defined function {}",
|
"Tried to redefine not yet defined function {}",
|
||||||
decl.name
|
decl.linkage_name(func_id),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -647,15 +655,19 @@ impl Module for JITModule {
|
|||||||
id: FuncId,
|
id: FuncId,
|
||||||
ctx: &mut cranelift_codegen::Context,
|
ctx: &mut cranelift_codegen::Context,
|
||||||
ctrl_plane: &mut ControlPlane,
|
ctrl_plane: &mut ControlPlane,
|
||||||
) -> ModuleResult<ModuleCompiledFunction> {
|
) -> ModuleResult<()> {
|
||||||
info!("defining function {}: {}", id, ctx.func.display());
|
info!("defining function {}: {}", id, ctx.func.display());
|
||||||
let decl = self.declarations.get_function_decl(id);
|
let decl = self.declarations.get_function_decl(id);
|
||||||
if !decl.linkage.is_definable() {
|
if !decl.linkage.is_definable() {
|
||||||
return Err(ModuleError::InvalidImportDefinition(decl.name.clone()));
|
return Err(ModuleError::InvalidImportDefinition(
|
||||||
|
decl.linkage_name(id).into_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.compiled_functions[id].is_none() {
|
if !self.compiled_functions[id].is_none() {
|
||||||
return Err(ModuleError::DuplicateDefinition(decl.name.to_owned()));
|
return Err(ModuleError::DuplicateDefinition(
|
||||||
|
decl.linkage_name(id).into_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.hotswap_enabled {
|
if self.hotswap_enabled {
|
||||||
@@ -678,9 +690,7 @@ impl Module for JITModule {
|
|||||||
let alignment = res.alignment as u64;
|
let alignment = res.alignment as u64;
|
||||||
let compiled_code = ctx.compiled_code().unwrap();
|
let compiled_code = ctx.compiled_code().unwrap();
|
||||||
|
|
||||||
let code_size = compiled_code.code_info().total_size;
|
let size = compiled_code.code_info().total_size as usize;
|
||||||
|
|
||||||
let size = code_size as usize;
|
|
||||||
let align = alignment
|
let align = alignment
|
||||||
.max(self.isa.function_alignment() as u64)
|
.max(self.isa.function_alignment() as u64)
|
||||||
.max(self.isa.symbol_alignment());
|
.max(self.isa.symbol_alignment());
|
||||||
@@ -705,7 +715,7 @@ impl Module for JITModule {
|
|||||||
.map(|reloc| ModuleReloc::from_mach_reloc(reloc, &ctx.func))
|
.map(|reloc| ModuleReloc::from_mach_reloc(reloc, &ctx.func))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
self.record_function_for_perf(ptr, size, &decl.name);
|
self.record_function_for_perf(ptr, size, &decl.linkage_name(id));
|
||||||
self.compiled_functions[id] = Some(CompiledBlob { ptr, size, relocs });
|
self.compiled_functions[id] = Some(CompiledBlob { ptr, size, relocs });
|
||||||
|
|
||||||
if self.isa.flags().is_pic() {
|
if self.isa.flags().is_pic() {
|
||||||
@@ -739,7 +749,7 @@ impl Module for JITModule {
|
|||||||
self.functions_to_finalize.push(id);
|
self.functions_to_finalize.push(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ModuleCompiledFunction { size: code_size })
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn define_function_bytes(
|
fn define_function_bytes(
|
||||||
@@ -749,20 +759,19 @@ impl Module for JITModule {
|
|||||||
alignment: u64,
|
alignment: u64,
|
||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
relocs: &[MachReloc],
|
relocs: &[MachReloc],
|
||||||
) -> ModuleResult<ModuleCompiledFunction> {
|
) -> ModuleResult<()> {
|
||||||
info!("defining function {} with bytes", id);
|
info!("defining function {} with bytes", id);
|
||||||
let total_size: u32 = match bytes.len().try_into() {
|
|
||||||
Ok(total_size) => total_size,
|
|
||||||
_ => Err(CodegenError::CodeTooLarge)?,
|
|
||||||
};
|
|
||||||
|
|
||||||
let decl = self.declarations.get_function_decl(id);
|
let decl = self.declarations.get_function_decl(id);
|
||||||
if !decl.linkage.is_definable() {
|
if !decl.linkage.is_definable() {
|
||||||
return Err(ModuleError::InvalidImportDefinition(decl.name.clone()));
|
return Err(ModuleError::InvalidImportDefinition(
|
||||||
|
decl.linkage_name(id).into_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.compiled_functions[id].is_none() {
|
if !self.compiled_functions[id].is_none() {
|
||||||
return Err(ModuleError::DuplicateDefinition(decl.name.to_owned()));
|
return Err(ModuleError::DuplicateDefinition(
|
||||||
|
decl.linkage_name(id).into_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let size = bytes.len();
|
let size = bytes.len();
|
||||||
@@ -782,7 +791,7 @@ impl Module for JITModule {
|
|||||||
ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, size);
|
ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.record_function_for_perf(ptr, size, &decl.name);
|
self.record_function_for_perf(ptr, size, &decl.linkage_name(id));
|
||||||
self.compiled_functions[id] = Some(CompiledBlob {
|
self.compiled_functions[id] = Some(CompiledBlob {
|
||||||
ptr,
|
ptr,
|
||||||
size,
|
size,
|
||||||
@@ -812,17 +821,21 @@ impl Module for JITModule {
|
|||||||
self.functions_to_finalize.push(id);
|
self.functions_to_finalize.push(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ModuleCompiledFunction { size: total_size })
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn define_data(&mut self, id: DataId, data: &DataDescription) -> ModuleResult<()> {
|
fn define_data(&mut self, id: DataId, data: &DataDescription) -> ModuleResult<()> {
|
||||||
let decl = self.declarations.get_data_decl(id);
|
let decl = self.declarations.get_data_decl(id);
|
||||||
if !decl.linkage.is_definable() {
|
if !decl.linkage.is_definable() {
|
||||||
return Err(ModuleError::InvalidImportDefinition(decl.name.clone()));
|
return Err(ModuleError::InvalidImportDefinition(
|
||||||
|
decl.linkage_name(id).into_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.compiled_data_objects[id].is_none() {
|
if !self.compiled_data_objects[id].is_none() {
|
||||||
return Err(ModuleError::DuplicateDefinition(decl.name.to_owned()));
|
return Err(ModuleError::DuplicateDefinition(
|
||||||
|
decl.linkage_name(id).into_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(!decl.tls, "JIT doesn't yet support TLS");
|
assert!(!decl.tls, "JIT doesn't yet support TLS");
|
||||||
|
|||||||
@@ -15,11 +15,15 @@ cranelift-codegen = { workspace = true }
|
|||||||
cranelift-control = { workspace = true }
|
cranelift-control = { workspace = true }
|
||||||
hashbrown = { workspace = true, optional = true }
|
hashbrown = { workspace = true, optional = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
|
serde = { version = "1.0.94", features = ["derive"], optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = ["cranelift-codegen/std"]
|
std = ["cranelift-codegen/std"]
|
||||||
core = ["hashbrown", "cranelift-codegen/core"]
|
core = ["hashbrown", "cranelift-codegen/core"]
|
||||||
|
|
||||||
|
# For dependent crates that want to serialize some parts of cranelift
|
||||||
|
enable-serde = ["serde", "cranelift-codegen/enable-serde"]
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
maintenance = { status = "experimental" }
|
maintenance = { status = "experimental" }
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use crate::ModuleExtName;
|
|||||||
|
|
||||||
/// This specifies how data is to be initialized.
|
/// This specifies how data is to be initialized.
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub enum Init {
|
pub enum Init {
|
||||||
/// This indicates that no initialization has been specified yet.
|
/// This indicates that no initialization has been specified yet.
|
||||||
Uninitialized,
|
Uninitialized,
|
||||||
@@ -41,6 +42,7 @@ impl Init {
|
|||||||
|
|
||||||
/// A description of a data object.
|
/// A description of a data object.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct DataDescription {
|
pub struct DataDescription {
|
||||||
/// How the data should be initialized.
|
/// How the data should be initialized.
|
||||||
pub init: Init,
|
pub init: Init,
|
||||||
|
|||||||
@@ -43,8 +43,7 @@ mod traps;
|
|||||||
pub use crate::data_context::{DataDescription, Init};
|
pub use crate::data_context::{DataDescription, Init};
|
||||||
pub use crate::module::{
|
pub use crate::module::{
|
||||||
DataDeclaration, DataId, FuncId, FuncOrDataId, FunctionDeclaration, Linkage, Module,
|
DataDeclaration, DataId, FuncId, FuncOrDataId, FunctionDeclaration, Linkage, Module,
|
||||||
ModuleCompiledFunction, ModuleDeclarations, ModuleError, ModuleExtName, ModuleReloc,
|
ModuleDeclarations, ModuleError, ModuleExtName, ModuleReloc, ModuleResult,
|
||||||
ModuleResult,
|
|
||||||
};
|
};
|
||||||
pub use crate::traps::TrapSite;
|
pub use crate::traps::TrapSite;
|
||||||
|
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ use crate::data_context::DataDescription;
|
|||||||
use core::fmt::Display;
|
use core::fmt::Display;
|
||||||
use cranelift_codegen::binemit::{CodeOffset, Reloc};
|
use cranelift_codegen::binemit::{CodeOffset, Reloc};
|
||||||
use cranelift_codegen::entity::{entity_impl, PrimaryMap};
|
use cranelift_codegen::entity::{entity_impl, PrimaryMap};
|
||||||
use cranelift_codegen::ir::Function;
|
use cranelift_codegen::ir::function::{Function, VersionMarker};
|
||||||
use cranelift_codegen::settings::SetError;
|
use cranelift_codegen::settings::SetError;
|
||||||
use cranelift_codegen::{binemit, MachReloc};
|
use cranelift_codegen::MachReloc;
|
||||||
use cranelift_codegen::{ir, isa, CodegenError, CompileError, Context};
|
use cranelift_codegen::{ir, isa, CodegenError, CompileError, Context};
|
||||||
use cranelift_control::ControlPlane;
|
use cranelift_control::ControlPlane;
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::{Cow, ToOwned};
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
|
|
||||||
/// A module relocation.
|
/// A module relocation.
|
||||||
@@ -55,6 +55,7 @@ impl ModuleReloc {
|
|||||||
|
|
||||||
/// A function identifier for use in the `Module` interface.
|
/// A function identifier for use in the `Module` interface.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct FuncId(u32);
|
pub struct FuncId(u32);
|
||||||
entity_impl!(FuncId, "funcid");
|
entity_impl!(FuncId, "funcid");
|
||||||
|
|
||||||
@@ -82,6 +83,7 @@ impl FuncId {
|
|||||||
|
|
||||||
/// A data object identifier for use in the `Module` interface.
|
/// A data object identifier for use in the `Module` interface.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct DataId(u32);
|
pub struct DataId(u32);
|
||||||
entity_impl!(DataId, "dataid");
|
entity_impl!(DataId, "dataid");
|
||||||
|
|
||||||
@@ -109,6 +111,7 @@ impl DataId {
|
|||||||
|
|
||||||
/// Linkage refers to where an entity is defined and who can see it.
|
/// Linkage refers to where an entity is defined and who can see it.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub enum Linkage {
|
pub enum Linkage {
|
||||||
/// Defined outside of a module.
|
/// Defined outside of a module.
|
||||||
Import,
|
Import,
|
||||||
@@ -167,6 +170,7 @@ impl Linkage {
|
|||||||
|
|
||||||
/// A declared name may refer to either a function or data declaration
|
/// A declared name may refer to either a function or data declaration
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub enum FuncOrDataId {
|
pub enum FuncOrDataId {
|
||||||
/// When it's a FuncId
|
/// When it's a FuncId
|
||||||
Func(FuncId),
|
Func(FuncId),
|
||||||
@@ -186,9 +190,10 @@ impl From<FuncOrDataId> for ModuleExtName {
|
|||||||
|
|
||||||
/// Information about a function which can be called.
|
/// Information about a function which can be called.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct FunctionDeclaration {
|
pub struct FunctionDeclaration {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub name: String,
|
pub name: Option<String>,
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub linkage: Linkage,
|
pub linkage: Linkage,
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
@@ -196,11 +201,29 @@ pub struct FunctionDeclaration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionDeclaration {
|
impl FunctionDeclaration {
|
||||||
fn merge(&mut self, linkage: Linkage, sig: &ir::Signature) -> Result<(), ModuleError> {
|
/// The linkage name of the function.
|
||||||
|
///
|
||||||
|
/// Synthesized from the given function id if it is an anonymous function.
|
||||||
|
pub fn linkage_name(&self, id: FuncId) -> Cow<'_, str> {
|
||||||
|
match &self.name {
|
||||||
|
Some(name) => Cow::Borrowed(name),
|
||||||
|
// Symbols starting with .L are completely omitted from the symbol table after linking.
|
||||||
|
// Using hexadecimal instead of decimal for slightly smaller symbol names and often
|
||||||
|
// slightly faster linking.
|
||||||
|
None => Cow::Owned(format!(".Lfn{:x}", id.as_u32())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn merge(
|
||||||
|
&mut self,
|
||||||
|
id: FuncId,
|
||||||
|
linkage: Linkage,
|
||||||
|
sig: &ir::Signature,
|
||||||
|
) -> Result<(), ModuleError> {
|
||||||
self.linkage = Linkage::merge(self.linkage, linkage);
|
self.linkage = Linkage::merge(self.linkage, linkage);
|
||||||
if &self.signature != sig {
|
if &self.signature != sig {
|
||||||
return Err(ModuleError::IncompatibleSignature(
|
return Err(ModuleError::IncompatibleSignature(
|
||||||
self.name.clone(),
|
self.linkage_name(id).into_owned(),
|
||||||
self.signature.clone(),
|
self.signature.clone(),
|
||||||
sig.clone(),
|
sig.clone(),
|
||||||
));
|
));
|
||||||
@@ -325,9 +348,10 @@ pub type ModuleResult<T> = Result<T, ModuleError>;
|
|||||||
|
|
||||||
/// Information about a data object which can be accessed.
|
/// Information about a data object which can be accessed.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct DataDeclaration {
|
pub struct DataDeclaration {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub name: String,
|
pub name: Option<String>,
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub linkage: Linkage,
|
pub linkage: Linkage,
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
@@ -337,6 +361,19 @@ pub struct DataDeclaration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DataDeclaration {
|
impl DataDeclaration {
|
||||||
|
/// The linkage name of the data object.
|
||||||
|
///
|
||||||
|
/// Synthesized from the given data id if it is an anonymous function.
|
||||||
|
pub fn linkage_name(&self, id: DataId) -> Cow<'_, str> {
|
||||||
|
match &self.name {
|
||||||
|
Some(name) => Cow::Borrowed(name),
|
||||||
|
// Symbols starting with .L are completely omitted from the symbol table after linking.
|
||||||
|
// Using hexadecimal instead of decimal for slightly smaller symbol names and often
|
||||||
|
// slightly faster linking.
|
||||||
|
None => Cow::Owned(format!(".Ldata{:x}", id.as_u32())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn merge(&mut self, linkage: Linkage, writable: bool, tls: bool) {
|
fn merge(&mut self, linkage: Linkage, writable: bool, tls: bool) {
|
||||||
self.linkage = Linkage::merge(self.linkage, linkage);
|
self.linkage = Linkage::merge(self.linkage, linkage);
|
||||||
self.writable = self.writable || writable;
|
self.writable = self.writable || writable;
|
||||||
@@ -349,6 +386,7 @@ impl DataDeclaration {
|
|||||||
|
|
||||||
/// A translated `ExternalName` into something global we can handle.
|
/// A translated `ExternalName` into something global we can handle.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
#[cfg_attr(feature = "enable-serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub enum ModuleExtName {
|
pub enum ModuleExtName {
|
||||||
/// User defined function, converted from `ExternalName::User`.
|
/// User defined function, converted from `ExternalName::User`.
|
||||||
User {
|
User {
|
||||||
@@ -384,11 +422,236 @@ impl Display for ModuleExtName {
|
|||||||
/// into `FunctionDeclaration`s and `DataDeclaration`s.
|
/// into `FunctionDeclaration`s and `DataDeclaration`s.
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct ModuleDeclarations {
|
pub struct ModuleDeclarations {
|
||||||
|
/// A version marker used to ensure that serialized clif ir is never deserialized with a
|
||||||
|
/// different version of Cranelift.
|
||||||
|
// Note: This must be the first field to ensure that Serde will deserialize it before
|
||||||
|
// attempting to deserialize other fields that are potentially changed between versions.
|
||||||
|
_version_marker: VersionMarker,
|
||||||
|
|
||||||
names: HashMap<String, FuncOrDataId>,
|
names: HashMap<String, FuncOrDataId>,
|
||||||
functions: PrimaryMap<FuncId, FunctionDeclaration>,
|
functions: PrimaryMap<FuncId, FunctionDeclaration>,
|
||||||
data_objects: PrimaryMap<DataId, DataDeclaration>,
|
data_objects: PrimaryMap<DataId, DataDeclaration>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "enable-serde")]
|
||||||
|
mod serialize {
|
||||||
|
// This is manually implementing Serialize and Deserialize to avoid serializing the names field,
|
||||||
|
// which can be entirely reconstructed from the functions and data_objects fields, saving space.
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use serde::de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Unexpected, Visitor};
|
||||||
|
use serde::ser::{Serialize, SerializeStruct, Serializer};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
fn get_names<E: Error>(
|
||||||
|
functions: &PrimaryMap<FuncId, FunctionDeclaration>,
|
||||||
|
data_objects: &PrimaryMap<DataId, DataDeclaration>,
|
||||||
|
) -> Result<HashMap<String, FuncOrDataId>, E> {
|
||||||
|
let mut names = HashMap::new();
|
||||||
|
for (func_id, decl) in functions.iter() {
|
||||||
|
if let Some(name) = &decl.name {
|
||||||
|
let old = names.insert(name.clone(), FuncOrDataId::Func(func_id));
|
||||||
|
if old.is_some() {
|
||||||
|
return Err(E::invalid_value(
|
||||||
|
Unexpected::Other("duplicate name"),
|
||||||
|
&"FunctionDeclaration's with no duplicate names",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (data_id, decl) in data_objects.iter() {
|
||||||
|
if let Some(name) = &decl.name {
|
||||||
|
let old = names.insert(name.clone(), FuncOrDataId::Data(data_id));
|
||||||
|
if old.is_some() {
|
||||||
|
return Err(E::invalid_value(
|
||||||
|
Unexpected::Other("duplicate name"),
|
||||||
|
&"DataDeclaration's with no duplicate names",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(names)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for ModuleDeclarations {
|
||||||
|
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
||||||
|
let ModuleDeclarations {
|
||||||
|
_version_marker,
|
||||||
|
functions,
|
||||||
|
data_objects,
|
||||||
|
names: _,
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
let mut state = s.serialize_struct("ModuleDeclarations", 4)?;
|
||||||
|
state.serialize_field("_version_marker", _version_marker)?;
|
||||||
|
state.serialize_field("functions", functions)?;
|
||||||
|
state.serialize_field("data_objects", data_objects)?;
|
||||||
|
state.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ModuleDeclarationsField {
|
||||||
|
VersionMarker,
|
||||||
|
Functions,
|
||||||
|
DataObjects,
|
||||||
|
Ignore,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ModuleDeclarationsFieldVisitor;
|
||||||
|
|
||||||
|
impl<'de> serde::de::Visitor<'de> for ModuleDeclarationsFieldVisitor {
|
||||||
|
type Value = ModuleDeclarationsField;
|
||||||
|
|
||||||
|
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
f.write_str("field identifier")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_u64<E: Error>(self, val: u64) -> Result<Self::Value, E> {
|
||||||
|
match val {
|
||||||
|
0u64 => Ok(ModuleDeclarationsField::VersionMarker),
|
||||||
|
1u64 => Ok(ModuleDeclarationsField::Functions),
|
||||||
|
2u64 => Ok(ModuleDeclarationsField::DataObjects),
|
||||||
|
_ => Ok(ModuleDeclarationsField::Ignore),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E: Error>(self, val: &str) -> Result<Self::Value, E> {
|
||||||
|
match val {
|
||||||
|
"_version_marker" => Ok(ModuleDeclarationsField::VersionMarker),
|
||||||
|
"functions" => Ok(ModuleDeclarationsField::Functions),
|
||||||
|
"data_objects" => Ok(ModuleDeclarationsField::DataObjects),
|
||||||
|
_ => Ok(ModuleDeclarationsField::Ignore),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_bytes<E: Error>(self, val: &[u8]) -> Result<Self::Value, E> {
|
||||||
|
match val {
|
||||||
|
b"_version_marker" => Ok(ModuleDeclarationsField::VersionMarker),
|
||||||
|
b"functions" => Ok(ModuleDeclarationsField::Functions),
|
||||||
|
b"data_objects" => Ok(ModuleDeclarationsField::DataObjects),
|
||||||
|
_ => Ok(ModuleDeclarationsField::Ignore),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for ModuleDeclarationsField {
|
||||||
|
#[inline]
|
||||||
|
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
|
||||||
|
d.deserialize_identifier(ModuleDeclarationsFieldVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ModuleDeclarationsVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for ModuleDeclarationsVisitor {
|
||||||
|
type Value = ModuleDeclarations;
|
||||||
|
|
||||||
|
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
f.write_str("struct ModuleDeclarations")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
|
||||||
|
let _version_marker = match seq.next_element()? {
|
||||||
|
Some(val) => val,
|
||||||
|
None => {
|
||||||
|
return Err(Error::invalid_length(
|
||||||
|
0usize,
|
||||||
|
&"struct ModuleDeclarations with 4 elements",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let functions = match seq.next_element()? {
|
||||||
|
Some(val) => val,
|
||||||
|
None => {
|
||||||
|
return Err(Error::invalid_length(
|
||||||
|
2usize,
|
||||||
|
&"struct ModuleDeclarations with 4 elements",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let data_objects = match seq.next_element()? {
|
||||||
|
Some(val) => val,
|
||||||
|
None => {
|
||||||
|
return Err(Error::invalid_length(
|
||||||
|
3usize,
|
||||||
|
&"struct ModuleDeclarations with 4 elements",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let names = get_names(&functions, &data_objects)?;
|
||||||
|
Ok(ModuleDeclarations {
|
||||||
|
_version_marker,
|
||||||
|
names,
|
||||||
|
functions,
|
||||||
|
data_objects,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
|
||||||
|
let mut _version_marker: Option<VersionMarker> = None;
|
||||||
|
let mut functions: Option<PrimaryMap<FuncId, FunctionDeclaration>> = None;
|
||||||
|
let mut data_objects: Option<PrimaryMap<DataId, DataDeclaration>> = None;
|
||||||
|
while let Some(key) = map.next_key::<ModuleDeclarationsField>()? {
|
||||||
|
match key {
|
||||||
|
ModuleDeclarationsField::VersionMarker => {
|
||||||
|
if _version_marker.is_some() {
|
||||||
|
return Err(Error::duplicate_field("_version_marker"));
|
||||||
|
}
|
||||||
|
_version_marker = Some(map.next_value()?);
|
||||||
|
}
|
||||||
|
ModuleDeclarationsField::Functions => {
|
||||||
|
if functions.is_some() {
|
||||||
|
return Err(Error::duplicate_field("functions"));
|
||||||
|
}
|
||||||
|
functions = Some(map.next_value()?);
|
||||||
|
}
|
||||||
|
ModuleDeclarationsField::DataObjects => {
|
||||||
|
if data_objects.is_some() {
|
||||||
|
return Err(Error::duplicate_field("data_objects"));
|
||||||
|
}
|
||||||
|
data_objects = Some(map.next_value()?);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
map.next_value::<serde::de::IgnoredAny>()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let _version_marker = match _version_marker {
|
||||||
|
Some(_version_marker) => _version_marker,
|
||||||
|
None => return Err(Error::missing_field("_version_marker")),
|
||||||
|
};
|
||||||
|
let functions = match functions {
|
||||||
|
Some(functions) => functions,
|
||||||
|
None => return Err(Error::missing_field("functions")),
|
||||||
|
};
|
||||||
|
let data_objects = match data_objects {
|
||||||
|
Some(data_objects) => data_objects,
|
||||||
|
None => return Err(Error::missing_field("data_objects")),
|
||||||
|
};
|
||||||
|
let names = get_names(&functions, &data_objects)?;
|
||||||
|
Ok(ModuleDeclarations {
|
||||||
|
_version_marker,
|
||||||
|
names,
|
||||||
|
functions,
|
||||||
|
data_objects,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for ModuleDeclarations {
|
||||||
|
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
|
||||||
|
d.deserialize_struct(
|
||||||
|
"ModuleDeclarations",
|
||||||
|
&["_version_marker", "functions", "data_objects"],
|
||||||
|
ModuleDeclarationsVisitor,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ModuleDeclarations {
|
impl ModuleDeclarations {
|
||||||
/// Get the module identifier for a given name, if that name
|
/// Get the module identifier for a given name, if that name
|
||||||
/// has been declared.
|
/// has been declared.
|
||||||
@@ -439,7 +702,7 @@ impl ModuleDeclarations {
|
|||||||
Occupied(entry) => match *entry.get() {
|
Occupied(entry) => match *entry.get() {
|
||||||
FuncOrDataId::Func(id) => {
|
FuncOrDataId::Func(id) => {
|
||||||
let existing = &mut self.functions[id];
|
let existing = &mut self.functions[id];
|
||||||
existing.merge(linkage, signature)?;
|
existing.merge(id, linkage, signature)?;
|
||||||
Ok((id, existing.linkage))
|
Ok((id, existing.linkage))
|
||||||
}
|
}
|
||||||
FuncOrDataId::Data(..) => {
|
FuncOrDataId::Data(..) => {
|
||||||
@@ -448,7 +711,7 @@ impl ModuleDeclarations {
|
|||||||
},
|
},
|
||||||
Vacant(entry) => {
|
Vacant(entry) => {
|
||||||
let id = self.functions.push(FunctionDeclaration {
|
let id = self.functions.push(FunctionDeclaration {
|
||||||
name: name.to_owned(),
|
name: Some(name.to_owned()),
|
||||||
linkage,
|
linkage,
|
||||||
signature: signature.clone(),
|
signature: signature.clone(),
|
||||||
});
|
});
|
||||||
@@ -464,11 +727,10 @@ impl ModuleDeclarations {
|
|||||||
signature: &ir::Signature,
|
signature: &ir::Signature,
|
||||||
) -> ModuleResult<FuncId> {
|
) -> ModuleResult<FuncId> {
|
||||||
let id = self.functions.push(FunctionDeclaration {
|
let id = self.functions.push(FunctionDeclaration {
|
||||||
name: String::new(),
|
name: None,
|
||||||
linkage: Linkage::Local,
|
linkage: Linkage::Local,
|
||||||
signature: signature.clone(),
|
signature: signature.clone(),
|
||||||
});
|
});
|
||||||
self.functions[id].name = format!(".L{:?}", id);
|
|
||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,7 +758,7 @@ impl ModuleDeclarations {
|
|||||||
},
|
},
|
||||||
Vacant(entry) => {
|
Vacant(entry) => {
|
||||||
let id = self.data_objects.push(DataDeclaration {
|
let id = self.data_objects.push(DataDeclaration {
|
||||||
name: name.to_owned(),
|
name: Some(name.to_owned()),
|
||||||
linkage,
|
linkage,
|
||||||
writable,
|
writable,
|
||||||
tls,
|
tls,
|
||||||
@@ -510,22 +772,15 @@ impl ModuleDeclarations {
|
|||||||
/// Declare an anonymous data object in this module.
|
/// Declare an anonymous data object in this module.
|
||||||
pub fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId> {
|
pub fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId> {
|
||||||
let id = self.data_objects.push(DataDeclaration {
|
let id = self.data_objects.push(DataDeclaration {
|
||||||
name: String::new(),
|
name: None,
|
||||||
linkage: Linkage::Local,
|
linkage: Linkage::Local,
|
||||||
writable,
|
writable,
|
||||||
tls,
|
tls,
|
||||||
});
|
});
|
||||||
self.data_objects[id].name = format!(".L{:?}", id);
|
|
||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information about the compiled function.
|
|
||||||
pub struct ModuleCompiledFunction {
|
|
||||||
/// The size of the compiled function.
|
|
||||||
pub size: binemit::CodeOffset,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A `Module` is a utility for collecting functions and data objects, and linking them together.
|
/// A `Module` is a utility for collecting functions and data objects, and linking them together.
|
||||||
pub trait Module {
|
pub trait Module {
|
||||||
/// Return the `TargetIsa` to compile for.
|
/// Return the `TargetIsa` to compile for.
|
||||||
@@ -660,11 +915,7 @@ pub trait Module {
|
|||||||
/// Note: After calling this function the given `Context` will contain the compiled function.
|
/// Note: After calling this function the given `Context` will contain the compiled function.
|
||||||
///
|
///
|
||||||
/// [`define_function_with_control_plane`]: Self::define_function_with_control_plane
|
/// [`define_function_with_control_plane`]: Self::define_function_with_control_plane
|
||||||
fn define_function(
|
fn define_function(&mut self, func: FuncId, ctx: &mut Context) -> ModuleResult<()> {
|
||||||
&mut self,
|
|
||||||
func: FuncId,
|
|
||||||
ctx: &mut Context,
|
|
||||||
) -> ModuleResult<ModuleCompiledFunction> {
|
|
||||||
self.define_function_with_control_plane(func, ctx, &mut ControlPlane::default())
|
self.define_function_with_control_plane(func, ctx, &mut ControlPlane::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -678,7 +929,7 @@ pub trait Module {
|
|||||||
func: FuncId,
|
func: FuncId,
|
||||||
ctx: &mut Context,
|
ctx: &mut Context,
|
||||||
ctrl_plane: &mut ControlPlane,
|
ctrl_plane: &mut ControlPlane,
|
||||||
) -> ModuleResult<ModuleCompiledFunction>;
|
) -> ModuleResult<()>;
|
||||||
|
|
||||||
/// Define a function, taking the function body from the given `bytes`.
|
/// Define a function, taking the function body from the given `bytes`.
|
||||||
///
|
///
|
||||||
@@ -694,7 +945,7 @@ pub trait Module {
|
|||||||
alignment: u64,
|
alignment: u64,
|
||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
relocs: &[MachReloc],
|
relocs: &[MachReloc],
|
||||||
) -> ModuleResult<ModuleCompiledFunction>;
|
) -> ModuleResult<()>;
|
||||||
|
|
||||||
/// Define a data object, producing the data contents from the given `DataContext`.
|
/// Define a data object, producing the data contents from the given `DataContext`.
|
||||||
fn define_data(&mut self, data_id: DataId, data: &DataDescription) -> ModuleResult<()>;
|
fn define_data(&mut self, data_id: DataId, data: &DataDescription) -> ModuleResult<()>;
|
||||||
@@ -776,11 +1027,7 @@ impl<M: Module> Module for &mut M {
|
|||||||
(**self).declare_data_in_data(data_id, data)
|
(**self).declare_data_in_data(data_id, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn define_function(
|
fn define_function(&mut self, func: FuncId, ctx: &mut Context) -> ModuleResult<()> {
|
||||||
&mut self,
|
|
||||||
func: FuncId,
|
|
||||||
ctx: &mut Context,
|
|
||||||
) -> ModuleResult<ModuleCompiledFunction> {
|
|
||||||
(**self).define_function(func, ctx)
|
(**self).define_function(func, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -789,7 +1036,7 @@ impl<M: Module> Module for &mut M {
|
|||||||
func: FuncId,
|
func: FuncId,
|
||||||
ctx: &mut Context,
|
ctx: &mut Context,
|
||||||
ctrl_plane: &mut ControlPlane,
|
ctrl_plane: &mut ControlPlane,
|
||||||
) -> ModuleResult<ModuleCompiledFunction> {
|
) -> ModuleResult<()> {
|
||||||
(**self).define_function_with_control_plane(func, ctx, ctrl_plane)
|
(**self).define_function_with_control_plane(func, ctx, ctrl_plane)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -800,7 +1047,7 @@ impl<M: Module> Module for &mut M {
|
|||||||
alignment: u64,
|
alignment: u64,
|
||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
relocs: &[MachReloc],
|
relocs: &[MachReloc],
|
||||||
) -> ModuleResult<ModuleCompiledFunction> {
|
) -> ModuleResult<()> {
|
||||||
(**self).define_function_bytes(func_id, func, alignment, bytes, relocs)
|
(**self).define_function_bytes(func_id, func, alignment, bytes, relocs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
//! Defines `ObjectModule`.
|
//! Defines `ObjectModule`.
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
|
use cranelift_codegen::binemit::{Addend, CodeOffset, Reloc};
|
||||||
use cranelift_codegen::entity::SecondaryMap;
|
use cranelift_codegen::entity::SecondaryMap;
|
||||||
use cranelift_codegen::isa::{OwnedTargetIsa, TargetIsa};
|
use cranelift_codegen::isa::{OwnedTargetIsa, TargetIsa};
|
||||||
use cranelift_codegen::{self, ir, MachReloc};
|
use cranelift_codegen::{self, ir, MachReloc};
|
||||||
use cranelift_codegen::{
|
|
||||||
binemit::{Addend, CodeOffset, Reloc},
|
|
||||||
CodegenError,
|
|
||||||
};
|
|
||||||
use cranelift_control::ControlPlane;
|
use cranelift_control::ControlPlane;
|
||||||
use cranelift_module::{
|
use cranelift_module::{
|
||||||
DataDescription, DataId, FuncId, Init, Linkage, Module, ModuleCompiledFunction,
|
DataDescription, DataId, FuncId, Init, Linkage, Module, ModuleDeclarations, ModuleError,
|
||||||
ModuleDeclarations, ModuleError, ModuleExtName, ModuleReloc, ModuleResult,
|
ModuleExtName, ModuleReloc, ModuleResult,
|
||||||
};
|
};
|
||||||
use log::info;
|
use log::info;
|
||||||
use object::write::{
|
use object::write::{
|
||||||
@@ -21,7 +18,6 @@ use object::{
|
|||||||
RelocationEncoding, RelocationKind, SectionKind, SymbolFlags, SymbolKind, SymbolScope,
|
RelocationEncoding, RelocationKind, SectionKind, SymbolFlags, SymbolKind, SymbolScope,
|
||||||
};
|
};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::TryInto;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use target_lexicon::PointerWidth;
|
use target_lexicon::PointerWidth;
|
||||||
|
|
||||||
@@ -135,8 +131,6 @@ pub struct ObjectModule {
|
|||||||
libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>,
|
libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>,
|
||||||
known_symbols: HashMap<ir::KnownSymbol, SymbolId>,
|
known_symbols: HashMap<ir::KnownSymbol, SymbolId>,
|
||||||
per_function_section: bool,
|
per_function_section: bool,
|
||||||
anon_func_number: u64,
|
|
||||||
anon_data_number: u64,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectModule {
|
impl ObjectModule {
|
||||||
@@ -156,8 +150,6 @@ impl ObjectModule {
|
|||||||
libcall_names: builder.libcall_names,
|
libcall_names: builder.libcall_names,
|
||||||
known_symbols: HashMap::new(),
|
known_symbols: HashMap::new(),
|
||||||
per_function_section: builder.per_function_section,
|
per_function_section: builder.per_function_section,
|
||||||
anon_func_number: 0,
|
|
||||||
anon_data_number: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -219,16 +211,15 @@ impl Module for ObjectModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn declare_anonymous_function(&mut self, signature: &ir::Signature) -> ModuleResult<FuncId> {
|
fn declare_anonymous_function(&mut self, signature: &ir::Signature) -> ModuleResult<FuncId> {
|
||||||
// Symbols starting with .L are completely omitted from the symbol table after linking.
|
|
||||||
// Using hexadecimal instead of decimal for slightly smaller symbol names and often slightly
|
|
||||||
// faster linking.
|
|
||||||
let name = format!(".Lfn{:x}", self.anon_func_number);
|
|
||||||
self.anon_func_number += 1;
|
|
||||||
|
|
||||||
let id = self.declarations.declare_anonymous_function(signature)?;
|
let id = self.declarations.declare_anonymous_function(signature)?;
|
||||||
|
|
||||||
let symbol_id = self.object.add_symbol(Symbol {
|
let symbol_id = self.object.add_symbol(Symbol {
|
||||||
name: name.as_bytes().to_vec(),
|
name: self
|
||||||
|
.declarations
|
||||||
|
.get_function_decl(id)
|
||||||
|
.linkage_name(id)
|
||||||
|
.into_owned()
|
||||||
|
.into_bytes(),
|
||||||
value: 0,
|
value: 0,
|
||||||
size: 0,
|
size: 0,
|
||||||
kind: SymbolKind::Text,
|
kind: SymbolKind::Text,
|
||||||
@@ -287,12 +278,6 @@ impl Module for ObjectModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId> {
|
fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId> {
|
||||||
// Symbols starting with .L are completely omitted from the symbol table after linking.
|
|
||||||
// Using hexadecimal instead of decimal for slightly smaller symbol names and often slightly
|
|
||||||
// faster linking.
|
|
||||||
let name = format!(".Ldata{:x}", self.anon_data_number);
|
|
||||||
self.anon_data_number += 1;
|
|
||||||
|
|
||||||
let id = self.declarations.declare_anonymous_data(writable, tls)?;
|
let id = self.declarations.declare_anonymous_data(writable, tls)?;
|
||||||
|
|
||||||
let kind = if tls {
|
let kind = if tls {
|
||||||
@@ -302,7 +287,12 @@ impl Module for ObjectModule {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let symbol_id = self.object.add_symbol(Symbol {
|
let symbol_id = self.object.add_symbol(Symbol {
|
||||||
name: name.as_bytes().to_vec(),
|
name: self
|
||||||
|
.declarations
|
||||||
|
.get_data_decl(id)
|
||||||
|
.linkage_name(id)
|
||||||
|
.into_owned()
|
||||||
|
.into_bytes(),
|
||||||
value: 0,
|
value: 0,
|
||||||
size: 0,
|
size: 0,
|
||||||
kind,
|
kind,
|
||||||
@@ -321,7 +311,7 @@ impl Module for ObjectModule {
|
|||||||
func_id: FuncId,
|
func_id: FuncId,
|
||||||
ctx: &mut cranelift_codegen::Context,
|
ctx: &mut cranelift_codegen::Context,
|
||||||
ctrl_plane: &mut ControlPlane,
|
ctrl_plane: &mut ControlPlane,
|
||||||
) -> ModuleResult<ModuleCompiledFunction> {
|
) -> ModuleResult<()> {
|
||||||
info!("defining function {}: {}", func_id, ctx.func.display());
|
info!("defining function {}: {}", func_id, ctx.func.display());
|
||||||
let mut code: Vec<u8> = Vec::new();
|
let mut code: Vec<u8> = Vec::new();
|
||||||
|
|
||||||
@@ -344,21 +334,20 @@ impl Module for ObjectModule {
|
|||||||
alignment: u64,
|
alignment: u64,
|
||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
relocs: &[MachReloc],
|
relocs: &[MachReloc],
|
||||||
) -> ModuleResult<ModuleCompiledFunction> {
|
) -> ModuleResult<()> {
|
||||||
info!("defining function {} with bytes", func_id);
|
info!("defining function {} with bytes", func_id);
|
||||||
let total_size: u32 = match bytes.len().try_into() {
|
|
||||||
Ok(total_size) => total_size,
|
|
||||||
_ => Err(CodegenError::CodeTooLarge)?,
|
|
||||||
};
|
|
||||||
|
|
||||||
let decl = self.declarations.get_function_decl(func_id);
|
let decl = self.declarations.get_function_decl(func_id);
|
||||||
if !decl.linkage.is_definable() {
|
if !decl.linkage.is_definable() {
|
||||||
return Err(ModuleError::InvalidImportDefinition(decl.name.clone()));
|
return Err(ModuleError::InvalidImportDefinition(
|
||||||
|
decl.linkage_name(func_id).into_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let &mut (symbol, ref mut defined) = self.functions[func_id].as_mut().unwrap();
|
let &mut (symbol, ref mut defined) = self.functions[func_id].as_mut().unwrap();
|
||||||
if *defined {
|
if *defined {
|
||||||
return Err(ModuleError::DuplicateDefinition(decl.name.clone()));
|
return Err(ModuleError::DuplicateDefinition(
|
||||||
|
decl.linkage_name(func_id).into_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
*defined = true;
|
*defined = true;
|
||||||
|
|
||||||
@@ -391,18 +380,22 @@ impl Module for ObjectModule {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ModuleCompiledFunction { size: total_size })
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn define_data(&mut self, data_id: DataId, data: &DataDescription) -> ModuleResult<()> {
|
fn define_data(&mut self, data_id: DataId, data: &DataDescription) -> ModuleResult<()> {
|
||||||
let decl = self.declarations.get_data_decl(data_id);
|
let decl = self.declarations.get_data_decl(data_id);
|
||||||
if !decl.linkage.is_definable() {
|
if !decl.linkage.is_definable() {
|
||||||
return Err(ModuleError::InvalidImportDefinition(decl.name.clone()));
|
return Err(ModuleError::InvalidImportDefinition(
|
||||||
|
decl.linkage_name(data_id).into_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let &mut (symbol, ref mut defined) = self.data_objects[data_id].as_mut().unwrap();
|
let &mut (symbol, ref mut defined) = self.data_objects[data_id].as_mut().unwrap();
|
||||||
if *defined {
|
if *defined {
|
||||||
return Err(ModuleError::DuplicateDefinition(decl.name.clone()));
|
return Err(ModuleError::DuplicateDefinition(
|
||||||
|
decl.linkage_name(data_id).into_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
*defined = true;
|
*defined = true;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user