Improvements to Modules API (#307)
* test-no_std: use cargo +nightly assume folks have rustup set to use stable by default * cretonne-module, -faerie, -simplejit: use new ModuleError enum CtonError is not really appropriate for use in the module system. Instead, create a new enum ModuleError, which implements failure::Fail (works with no_std). Translate existing panics and unimplemented error cases to return ModuleErrors. * cretonne-faerie: export FaerieProduct * cretonne-module: expose FuncOrDataId, and Module::get_name to lookup This is helpful for looking up a name that has already been declared. Also, implement FuncOrDataId -> ExternalName conversion. * cretonne-faerie: depend on faerie 0.3.0 which has bugfix for data relocations * cretonne-module: change InvalidDefinition to InvalidImportDefinition per dan's code review. plus another typo fix * cretonne-faerie: add optional manifest of all traps from codegen * cretonne-module: provide more context in panics * cretonne-faerie: updates to docs * cretonne-faerie: return an Err instead of debug_assert when isa not pic
This commit is contained in:
@@ -3,13 +3,25 @@
|
||||
use container;
|
||||
use cretonne_codegen::binemit::{Addend, CodeOffset, Reloc, RelocSink, NullTrapSink};
|
||||
use cretonne_codegen::isa::TargetIsa;
|
||||
use cretonne_codegen::result::CtonError;
|
||||
use cretonne_codegen::{self, binemit, ir};
|
||||
use cretonne_module::{Backend, DataContext, Linkage, ModuleNamespace, Init, DataDescription};
|
||||
use faerie;
|
||||
use cretonne_module::{Backend, DataContext, Linkage, ModuleNamespace, Init, DataDescription,
|
||||
ModuleError};
|
||||
use failure::Error;
|
||||
use faerie;
|
||||
use std::fs::File;
|
||||
use target;
|
||||
use traps::{FaerieTrapManifest, FaerieTrapSink};
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Setting to enable collection of traps. Setting this to `Enabled` in
|
||||
/// `FaerieBuilder` means that a `FaerieTrapManifest` will be present
|
||||
/// in the `FaerieProduct`.
|
||||
pub enum FaerieTrapCollection {
|
||||
/// `FaerieProduct::trap_manifest` will be `None`
|
||||
Disabled,
|
||||
/// `FaerieProduct::trap_manifest` will be `Some`
|
||||
Enabled,
|
||||
}
|
||||
|
||||
/// A builder for `FaerieBackend`.
|
||||
pub struct FaerieBuilder {
|
||||
@@ -17,6 +29,7 @@ pub struct FaerieBuilder {
|
||||
name: String,
|
||||
format: container::Format,
|
||||
faerie_target: faerie::Target,
|
||||
collect_traps: FaerieTrapCollection,
|
||||
}
|
||||
|
||||
impl FaerieBuilder {
|
||||
@@ -24,21 +37,28 @@ impl FaerieBuilder {
|
||||
/// can be passed to
|
||||
/// [`Module::new`](cretonne_module/struct.Module.html#method.new].
|
||||
///
|
||||
/// Note: To support calls JIT'd functions from Rust or other compiled
|
||||
/// code, it's necessary for the `call_conv` setting in `isa`'s flags
|
||||
/// to match the host platform.
|
||||
/// Faerie output requires that TargetIsa have PIC (Position Independent Code) enabled.
|
||||
///
|
||||
/// `collect_traps` setting determines whether trap information is collected in a
|
||||
/// `FaerieTrapManifest` available in the `FaerieProduct`.
|
||||
pub fn new(
|
||||
isa: Box<TargetIsa>,
|
||||
name: String,
|
||||
format: container::Format,
|
||||
) -> Result<Self, Error> {
|
||||
debug_assert!(isa.flags().is_pic(), "faerie requires PIC");
|
||||
collect_traps: FaerieTrapCollection,
|
||||
) -> Result<Self, ModuleError> {
|
||||
if !isa.flags().is_pic() {
|
||||
return Err(ModuleError::Backend(
|
||||
"faerie requires TargetIsa be PIC".to_owned(),
|
||||
));
|
||||
}
|
||||
let faerie_target = target::translate(&*isa)?;
|
||||
Ok(Self {
|
||||
isa,
|
||||
name,
|
||||
format,
|
||||
faerie_target,
|
||||
collect_traps,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -48,6 +68,7 @@ pub struct FaerieBackend {
|
||||
isa: Box<TargetIsa>,
|
||||
artifact: faerie::Artifact,
|
||||
format: container::Format,
|
||||
trap_manifest: Option<FaerieTrapManifest>,
|
||||
}
|
||||
|
||||
pub struct FaerieCompiledFunction {}
|
||||
@@ -75,6 +96,10 @@ impl Backend for FaerieBackend {
|
||||
isa: builder.isa,
|
||||
artifact: faerie::Artifact::new(builder.faerie_target, builder.name),
|
||||
format: builder.format,
|
||||
trap_manifest: match builder.collect_traps {
|
||||
FaerieTrapCollection::Enabled => Some(FaerieTrapManifest::new()),
|
||||
FaerieTrapCollection::Disabled => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +125,7 @@ impl Backend for FaerieBackend {
|
||||
ctx: &cretonne_codegen::Context,
|
||||
namespace: &ModuleNamespace<Self>,
|
||||
code_size: u32,
|
||||
) -> Result<FaerieCompiledFunction, CtonError> {
|
||||
) -> Result<FaerieCompiledFunction, ModuleError> {
|
||||
let mut code: Vec<u8> = Vec::with_capacity(code_size as usize);
|
||||
code.resize(code_size as usize, 0);
|
||||
|
||||
@@ -112,18 +137,29 @@ impl Backend for FaerieBackend {
|
||||
name,
|
||||
namespace,
|
||||
};
|
||||
// Ignore traps for now. For now, frontends should just avoid generating code
|
||||
// that traps.
|
||||
let mut trap_sink = NullTrapSink {};
|
||||
|
||||
unsafe {
|
||||
ctx.emit_to_memory(
|
||||
&*self.isa,
|
||||
code.as_mut_ptr(),
|
||||
&mut reloc_sink,
|
||||
&mut trap_sink,
|
||||
)
|
||||
};
|
||||
if let Some(ref mut trap_manifest) = self.trap_manifest {
|
||||
let mut trap_sink = FaerieTrapSink::new(name, code_size);
|
||||
unsafe {
|
||||
ctx.emit_to_memory(
|
||||
&*self.isa,
|
||||
code.as_mut_ptr(),
|
||||
&mut reloc_sink,
|
||||
&mut trap_sink,
|
||||
)
|
||||
};
|
||||
trap_manifest.add_sink(trap_sink);
|
||||
} else {
|
||||
let mut trap_sink = NullTrapSink {};
|
||||
unsafe {
|
||||
ctx.emit_to_memory(
|
||||
&*self.isa,
|
||||
code.as_mut_ptr(),
|
||||
&mut reloc_sink,
|
||||
&mut trap_sink,
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
self.artifact.define(name, code).expect(
|
||||
@@ -137,7 +173,7 @@ impl Backend for FaerieBackend {
|
||||
name: &str,
|
||||
data_ctx: &DataContext,
|
||||
namespace: &ModuleNamespace<Self>,
|
||||
) -> Result<FaerieCompiledData, CtonError> {
|
||||
) -> Result<FaerieCompiledData, ModuleError> {
|
||||
let &DataDescription {
|
||||
writable: _writable,
|
||||
ref init,
|
||||
@@ -161,8 +197,6 @@ impl Backend for FaerieBackend {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Change the signature of this function to use something other
|
||||
// than `CtonError`, as `CtonError` can't convey faerie's errors.
|
||||
for &(offset, id) in function_relocs {
|
||||
let to = &namespace.get_function_decl(&function_decls[id]).name;
|
||||
self.artifact
|
||||
@@ -171,7 +205,7 @@ impl Backend for FaerieBackend {
|
||||
to,
|
||||
at: offset as usize,
|
||||
})
|
||||
.map_err(|_e| CtonError::InvalidInput)?;
|
||||
.map_err(|e| ModuleError::Backend(format!("{}", e)))?;
|
||||
}
|
||||
for &(offset, id, addend) in data_relocs {
|
||||
debug_assert_eq!(
|
||||
@@ -186,7 +220,7 @@ impl Backend for FaerieBackend {
|
||||
to,
|
||||
at: offset as usize,
|
||||
})
|
||||
.map_err(|_e| CtonError::InvalidInput)?;
|
||||
.map_err(|e| ModuleError::Backend(format!("{}", e)))?;
|
||||
}
|
||||
|
||||
self.artifact.define(name, bytes).expect(
|
||||
@@ -230,6 +264,7 @@ impl Backend for FaerieBackend {
|
||||
FaerieProduct {
|
||||
artifact: self.artifact,
|
||||
format: self.format,
|
||||
trap_manifest: self.trap_manifest,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,7 +273,12 @@ impl Backend for FaerieBackend {
|
||||
/// [`finish`](../cretonne_module/struct.Module.html#method.finish) function.
|
||||
/// It provides functions for writing out the object file to memory or a file.
|
||||
pub struct FaerieProduct {
|
||||
artifact: faerie::Artifact,
|
||||
/// Faerie artifact with all functions, data, and links from the module defined
|
||||
pub artifact: faerie::Artifact,
|
||||
/// Optional trap manifest. Contains `FaerieTrapManifest` when `FaerieBuilder.collect_traps` is
|
||||
/// set to `FaerieTrapCollection::Enabled`.
|
||||
pub trap_manifest: Option<FaerieTrapManifest>,
|
||||
/// The format that the builder specified for output.
|
||||
format: container::Format,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user