@ -10,12 +10,12 @@ use crate::data_context::DataDescription;
use core ::fmt ::Display ;
use cranelift_codegen ::binemit ::{ CodeOffset , Reloc } ;
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 ::{ binemit , MachReloc } ;
use cranelift_codegen ::MachReloc ;
use cranelift_codegen ::{ ir , isa , CodegenError , CompileError , Context } ;
use cranelift_control ::ControlPlane ;
use std ::borrow ::ToOwned ;
use std ::borrow ::{ Cow , ToOwned } ;
use std ::string ::String ;
/// A module relocation.
@ -55,6 +55,7 @@ impl ModuleReloc {
/// A function identifier for use in the `Module` interface.
#[ derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord) ]
#[ cfg_attr(feature = " enable-serde " , derive(serde::Serialize, serde::Deserialize)) ]
pub struct FuncId ( u32 ) ;
entity_impl ! ( FuncId , "funcid" ) ;
@ -82,6 +83,7 @@ impl FuncId {
/// A data object identifier for use in the `Module` interface.
#[ derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord) ]
#[ cfg_attr(feature = " enable-serde " , derive(serde::Serialize, serde::Deserialize)) ]
pub struct DataId ( u32 ) ;
entity_impl ! ( DataId , "dataid" ) ;
@ -109,6 +111,7 @@ impl DataId {
/// Linkage refers to where an entity is defined and who can see it.
#[ derive(Copy, Clone, Debug, PartialEq, Eq) ]
#[ cfg_attr(feature = " enable-serde " , derive(serde::Serialize, serde::Deserialize)) ]
pub enum Linkage {
/// Defined outside of a module.
Import ,
@ -167,6 +170,7 @@ impl Linkage {
/// A declared name may refer to either a function or data declaration
#[ derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug) ]
#[ cfg_attr(feature = " enable-serde " , derive(serde::Serialize, serde::Deserialize)) ]
pub enum FuncOrDataId {
/// When it's a FuncId
Func ( FuncId ) ,
@ -186,9 +190,10 @@ impl From<FuncOrDataId> for ModuleExtName {
/// Information about a function which can be called.
#[ derive(Debug) ]
#[ cfg_attr(feature = " enable-serde " , derive(serde::Serialize, serde::Deserialize)) ]
pub struct FunctionDeclaration {
#[ allow(missing_docs) ]
pub name : String ,
pub name : Option < String > ,
#[ allow(missing_docs) ]
pub linkage : Linkage ,
#[ allow(missing_docs) ]
@ -196,11 +201,29 @@ pub struct 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 ) ;
if & self . signature ! = sig {
return Err ( ModuleError ::IncompatibleSignature (
self . name . clone ( ) ,
self . linkage_name ( id ) . into_owned ( ) ,
self . signature . clone ( ) ,
sig . clone ( ) ,
) ) ;
@ -325,9 +348,10 @@ pub type ModuleResult<T> = Result<T, ModuleError>;
/// Information about a data object which can be accessed.
#[ derive(Debug) ]
#[ cfg_attr(feature = " enable-serde " , derive(serde::Serialize, serde::Deserialize)) ]
pub struct DataDeclaration {
#[ allow(missing_docs) ]
pub name : String ,
pub name : Option < String > ,
#[ allow(missing_docs) ]
pub linkage : Linkage ,
#[ allow(missing_docs) ]
@ -337,6 +361,19 @@ pub struct 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 ) {
self . linkage = Linkage ::merge ( self . linkage , linkage ) ;
self . writable = self . writable | | writable ;
@ -349,6 +386,7 @@ impl DataDeclaration {
/// A translated `ExternalName` into something global we can handle.
#[ derive(Clone, Debug) ]
#[ cfg_attr(feature = " enable-serde " , derive(serde::Serialize, serde::Deserialize)) ]
pub enum ModuleExtName {
/// User defined function, converted from `ExternalName::User`.
User {
@ -384,11 +422,236 @@ impl Display for ModuleExtName {
/// into `FunctionDeclaration`s and `DataDeclaration`s.
#[ derive(Debug, Default) ]
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 > ,
functions : PrimaryMap < FuncId , FunctionDeclaration > ,
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 {
0 u64 = > Ok ( ModuleDeclarationsField ::VersionMarker ) ,
1 u64 = > Ok ( ModuleDeclarationsField ::Functions ) ,
2 u64 = > 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 (
0 usize ,
& "struct ModuleDeclarations with 4 elements" ,
) ) ;
}
} ;
let functions = match seq . next_element ( ) ? {
Some ( val ) = > val ,
None = > {
return Err ( Error ::invalid_length (
2 usize ,
& "struct ModuleDeclarations with 4 elements" ,
) ) ;
}
} ;
let data_objects = match seq . next_element ( ) ? {
Some ( val ) = > val ,
None = > {
return Err ( Error ::invalid_length (
3 usize ,
& "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 {
/// Get the module identifier for a given name, if that name
/// has been declared.
@ -439,7 +702,7 @@ impl ModuleDeclarations {
Occupied ( entry ) = > match * entry . get ( ) {
FuncOrDataId ::Func ( id ) = > {
let existing = & mut self . functions [ id ] ;
existing . merge ( linkage , signature ) ? ;
existing . merge ( id , linkage , signature ) ? ;
Ok ( ( id , existing . linkage ) )
}
FuncOrDataId ::Data ( . . ) = > {
@ -448,7 +711,7 @@ impl ModuleDeclarations {
} ,
Vacant ( entry ) = > {
let id = self . functions . push ( FunctionDeclaration {
name : name . to_owned ( ) ,
name : Some ( name . to_owned ( ) ) ,
linkage ,
signature : signature . clone ( ) ,
} ) ;
@ -464,11 +727,10 @@ impl ModuleDeclarations {
signature : & ir ::Signature ,
) -> ModuleResult < FuncId > {
let id = self . functions . push ( FunctionDeclaration {
name : String ::new ( ) ,
name : None ,
linkage : Linkage ::Local ,
signature : signature . clone ( ) ,
} ) ;
self . functions [ id ] . name = format ! ( ".L{:?}" , id ) ;
Ok ( id )
}
@ -496,7 +758,7 @@ impl ModuleDeclarations {
} ,
Vacant ( entry ) = > {
let id = self . data_objects . push ( DataDeclaration {
name : name . to_owned ( ) ,
name : Some ( name . to_owned ( ) ) ,
linkage ,
writable ,
tls ,
@ -510,22 +772,15 @@ impl ModuleDeclarations {
/// 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 ( ) ,
name : None ,
linkage : Linkage ::Local ,
writable ,
tls ,
} ) ;
self . data_objects [ id ] . name = format ! ( ".L{:?}" , 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.
pub trait Module {
/// 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.
///
/// [`define_function_with_control_plane`]: Self::define_function_with_control_plane
fn define_function (
& mut self ,
func : FuncId ,
ctx : & mut Context ,
) -> ModuleResult < ModuleCompiledFunction > {
fn define_function ( & mut self , func : FuncId , ctx : & mut Context ) -> ModuleResult < ( ) > {
self . define_function_with_control_plane ( func , ctx , & mut ControlPlane ::default ( ) )
}
@ -678,7 +929,7 @@ pub trait Module {
func : FuncId ,
ctx : & mut Context ,
ctrl_plane : & mut ControlPlane ,
) -> ModuleResult < ModuleCompiledFunction > ;
) -> ModuleResult < ( ) > ;
/// Define a function, taking the function body from the given `bytes`.
///
@ -694,7 +945,7 @@ pub trait Module {
alignment : u64 ,
bytes : & [ u8 ] ,
relocs : & [ MachReloc ] ,
) -> ModuleResult < ModuleCompiledFunction > ;
) -> ModuleResult < ( ) > ;
/// Define a data object, producing the data contents from the given `DataContext`.
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 )
}
fn define_function (
& mut self ,
func : FuncId ,
ctx : & mut Context ,
) -> ModuleResult < ModuleCompiledFunction > {
fn define_function ( & mut self , func : FuncId , ctx : & mut Context ) -> ModuleResult < ( ) > {
( * * self ) . define_function ( func , ctx )
}
@ -789,7 +1036,7 @@ impl<M: Module> Module for &mut M {
func : FuncId ,
ctx : & mut Context ,
ctrl_plane : & mut ControlPlane ,
) -> ModuleResult < ModuleCompiledFunction > {
) -> ModuleResult < ( ) > {
( * * self ) . define_function_with_control_plane ( func , ctx , ctrl_plane )
}
@ -800,7 +1047,7 @@ impl<M: Module> Module for &mut M {
alignment : u64 ,
bytes : & [ u8 ] ,
relocs : & [ MachReloc ] ,
) -> ModuleResult < ModuleCompiledFunction > {
) -> ModuleResult < ( ) > {
( * * self ) . define_function_bytes ( func_id , func , alignment , bytes , relocs )
}