change Module::define_function to take TrapSink instances

Experience with the `define_function` API has shown that returning
borrowed slices of `TrapSite` is not ideal: the returned slice
represents a borrow on the entire `Module`, which makes calling back
into methods taking `&mut self` a bit tricky.

To eliminate the problem, let's require the callers of `define_function`
to provide `TrapSink` instances.  This style of API enables them to
control when and how traps are collected, and makes the `object` and
`faerie` backends simpler/more efficient by not having to worry about
trap collection.
This commit is contained in:
Nathan Froyd
2020-03-24 09:46:25 -04:00
parent 222a73c150
commit dcabb55776
11 changed files with 97 additions and 272 deletions

View File

@@ -1,38 +1,25 @@
//! Defines `FaerieBackend`. //! Defines `FaerieBackend`.
use crate::container; use crate::container;
use crate::traps::{FaerieTrapManifest, FaerieTrapSink};
use anyhow::anyhow; use anyhow::anyhow;
use cranelift_codegen::binemit::{ use cranelift_codegen::binemit::{
Addend, CodeOffset, NullStackmapSink, NullTrapSink, Reloc, RelocSink, Stackmap, StackmapSink, Addend, CodeOffset, NullStackmapSink, Reloc, RelocSink, Stackmap, StackmapSink, TrapSink,
}; };
use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::isa::TargetIsa;
use cranelift_codegen::{self, binemit, ir}; use cranelift_codegen::{self, binemit, ir};
use cranelift_module::{ use cranelift_module::{
Backend, DataContext, DataDescription, DataId, FuncId, Init, Linkage, ModuleError, Backend, DataContext, DataDescription, DataId, FuncId, Init, Linkage, ModuleError,
ModuleNamespace, ModuleResult, TrapSite, ModuleNamespace, ModuleResult,
}; };
use faerie; use faerie;
use std::convert::TryInto; use std::convert::TryInto;
use std::fs::File; use std::fs::File;
use target_lexicon::Triple; use target_lexicon::Triple;
#[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`. /// A builder for `FaerieBackend`.
pub struct FaerieBuilder { pub struct FaerieBuilder {
isa: Box<dyn TargetIsa>, isa: Box<dyn TargetIsa>,
name: String, name: String,
collect_traps: FaerieTrapCollection,
libcall_names: Box<dyn Fn(ir::LibCall) -> String>, libcall_names: Box<dyn Fn(ir::LibCall) -> String>,
} }
@@ -43,9 +30,6 @@ impl FaerieBuilder {
/// ///
/// Faerie output requires that TargetIsa have PIC (Position Independent Code) enabled. /// 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`.
///
/// The `libcall_names` function provides a way to translate `cranelift_codegen`'s `ir::LibCall` /// The `libcall_names` function provides a way to translate `cranelift_codegen`'s `ir::LibCall`
/// enum to symbols. LibCalls are inserted in the IR as part of the legalization for certain /// enum to symbols. LibCalls are inserted in the IR as part of the legalization for certain
/// floating point instructions, and for stack probes. If you don't know what to use for this /// floating point instructions, and for stack probes. If you don't know what to use for this
@@ -53,7 +37,6 @@ impl FaerieBuilder {
pub fn new( pub fn new(
isa: Box<dyn TargetIsa>, isa: Box<dyn TargetIsa>,
name: String, name: String,
collect_traps: FaerieTrapCollection,
libcall_names: Box<dyn Fn(ir::LibCall) -> String>, libcall_names: Box<dyn Fn(ir::LibCall) -> String>,
) -> ModuleResult<Self> { ) -> ModuleResult<Self> {
if !isa.flags().is_pic() { if !isa.flags().is_pic() {
@@ -64,7 +47,6 @@ impl FaerieBuilder {
Ok(Self { Ok(Self {
isa, isa,
name, name,
collect_traps,
libcall_names, libcall_names,
}) })
} }
@@ -76,7 +58,6 @@ impl FaerieBuilder {
pub struct FaerieBackend { pub struct FaerieBackend {
isa: Box<dyn TargetIsa>, isa: Box<dyn TargetIsa>,
artifact: faerie::Artifact, artifact: faerie::Artifact,
trap_manifest: Option<FaerieTrapManifest>,
libcall_names: Box<dyn Fn(ir::LibCall) -> String>, libcall_names: Box<dyn Fn(ir::LibCall) -> String>,
} }
@@ -112,10 +93,6 @@ impl Backend for FaerieBackend {
Self { Self {
artifact: faerie::Artifact::new(builder.isa.triple().clone(), builder.name), artifact: faerie::Artifact::new(builder.isa.triple().clone(), builder.name),
isa: builder.isa, isa: builder.isa,
trap_manifest: match builder.collect_traps {
FaerieTrapCollection::Enabled => Some(FaerieTrapManifest::new()),
FaerieTrapCollection::Disabled => None,
},
libcall_names: builder.libcall_names, libcall_names: builder.libcall_names,
} }
} }
@@ -145,18 +122,21 @@ impl Backend for FaerieBackend {
.expect("inconsistent declarations"); .expect("inconsistent declarations");
} }
fn define_function( fn define_function<TS>(
&mut self, &mut self,
_id: FuncId, _id: FuncId,
name: &str, name: &str,
ctx: &cranelift_codegen::Context, ctx: &cranelift_codegen::Context,
namespace: &ModuleNamespace<Self>, namespace: &ModuleNamespace<Self>,
total_size: u32, total_size: u32,
) -> ModuleResult<(FaerieCompiledFunction, &[TrapSite])> { trap_sink: &mut TS,
) -> ModuleResult<FaerieCompiledFunction>
where
TS: TrapSink,
{
let mut code: Vec<u8> = vec![0; total_size as usize]; let mut code: Vec<u8> = vec![0; total_size as usize];
// TODO: Replace this with FaerieStackmapSink once it is implemented. // TODO: Replace this with FaerieStackmapSink once it is implemented.
let mut stackmap_sink = NullStackmapSink {}; let mut stackmap_sink = NullStackmapSink {};
let mut traps: &[TrapSite] = &[];
// Non-lexical lifetimes would obviate the braces here. // Non-lexical lifetimes would obviate the braces here.
{ {
@@ -168,30 +148,15 @@ impl Backend for FaerieBackend {
libcall_names: &*self.libcall_names, libcall_names: &*self.libcall_names,
}; };
if let Some(ref mut trap_manifest) = self.trap_manifest {
let mut trap_sink = FaerieTrapSink::new(name, total_size);
unsafe { unsafe {
ctx.emit_to_memory( ctx.emit_to_memory(
&*self.isa, &*self.isa,
code.as_mut_ptr(), code.as_mut_ptr(),
&mut reloc_sink, &mut reloc_sink,
&mut trap_sink, trap_sink,
&mut stackmap_sink, &mut stackmap_sink,
) )
}; };
traps = 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,
&mut stackmap_sink,
)
};
}
} }
// because `define` will take ownership of code, this is our last chance // because `define` will take ownership of code, this is our last chance
@@ -201,7 +166,7 @@ impl Backend for FaerieBackend {
.define(name, code) .define(name, code)
.expect("inconsistent declaration"); .expect("inconsistent declaration");
Ok((FaerieCompiledFunction { code_length }, traps)) Ok(FaerieCompiledFunction { code_length })
} }
fn define_function_bytes( fn define_function_bytes(
@@ -210,24 +175,17 @@ impl Backend for FaerieBackend {
name: &str, name: &str,
bytes: &[u8], bytes: &[u8],
_namespace: &ModuleNamespace<Self>, _namespace: &ModuleNamespace<Self>,
traps: Vec<TrapSite>, ) -> ModuleResult<FaerieCompiledFunction> {
) -> ModuleResult<(FaerieCompiledFunction, &[TrapSite])> {
let code_length: u32 = match bytes.len().try_into() { let code_length: u32 = match bytes.len().try_into() {
Ok(code_length) => code_length, Ok(code_length) => code_length,
_ => Err(ModuleError::FunctionTooLarge(name.to_string()))?, _ => Err(ModuleError::FunctionTooLarge(name.to_string()))?,
}; };
let mut ret_traps: &[TrapSite] = &[];
if let Some(ref mut trap_manifest) = self.trap_manifest {
let trap_sink = FaerieTrapSink::new_with_sites(name, code_length, traps);
ret_traps = trap_manifest.add_sink(trap_sink);
}
self.artifact self.artifact
.define(name, bytes.to_vec()) .define(name, bytes.to_vec())
.expect("inconsistent declaration"); .expect("inconsistent declaration");
Ok((FaerieCompiledFunction { code_length }, ret_traps)) Ok(FaerieCompiledFunction { code_length })
} }
fn define_data( fn define_data(
@@ -345,7 +303,6 @@ impl Backend for FaerieBackend {
fn finish(self, _namespace: &ModuleNamespace<Self>) -> FaerieProduct { fn finish(self, _namespace: &ModuleNamespace<Self>) -> FaerieProduct {
FaerieProduct { FaerieProduct {
artifact: self.artifact, artifact: self.artifact,
trap_manifest: self.trap_manifest,
} }
} }
} }
@@ -357,9 +314,6 @@ impl Backend for FaerieBackend {
pub struct FaerieProduct { pub struct FaerieProduct {
/// Faerie artifact with all functions, data, and links from the module defined /// Faerie artifact with all functions, data, and links from the module defined
pub artifact: faerie::Artifact, pub artifact: faerie::Artifact,
/// Optional trap manifest. Contains `FaerieTrapManifest` when `FaerieBuilder.collect_traps` is
/// set to `FaerieTrapCollection::Enabled`.
pub trap_manifest: Option<FaerieTrapManifest>,
} }
impl FaerieProduct { impl FaerieProduct {

View File

@@ -27,9 +27,8 @@
mod backend; mod backend;
mod container; mod container;
pub mod traps;
pub use crate::backend::{FaerieBackend, FaerieBuilder, FaerieProduct, FaerieTrapCollection}; pub use crate::backend::{FaerieBackend, FaerieBuilder, FaerieProduct};
pub use crate::container::Format; pub use crate::container::Format;
/// Version number of this crate. /// Version number of this crate.

View File

@@ -1,66 +0,0 @@
//! Faerie trap manifests record every `TrapCode` that cranelift outputs during code generation,
//! for every function in the module. This data may be useful at runtime.
use cranelift_codegen::{binemit, ir};
use cranelift_module::TrapSite;
/// Record of the trap sites for a given function
#[derive(Debug)]
pub struct FaerieTrapSink {
/// Name of function
pub name: String,
/// Total code size of function
pub code_size: u32,
/// All trap sites collected in function
pub sites: Vec<TrapSite>,
}
impl FaerieTrapSink {
/// Create an empty `FaerieTrapSink`
pub fn new(name: &str, code_size: u32) -> Self {
Self {
sites: Vec::new(),
name: name.to_owned(),
code_size,
}
}
/// Create a `FaerieTrapSink` pre-populated with `traps`
pub fn new_with_sites(name: &str, code_size: u32, traps: Vec<TrapSite>) -> Self {
Self {
sites: traps,
name: name.to_owned(),
code_size,
}
}
}
impl binemit::TrapSink for FaerieTrapSink {
fn trap(&mut self, offset: binemit::CodeOffset, srcloc: ir::SourceLoc, code: ir::TrapCode) {
self.sites.push(TrapSite {
offset,
srcloc,
code,
});
}
}
/// Collection of all `FaerieTrapSink`s for the module
#[derive(Debug)]
pub struct FaerieTrapManifest {
/// All `FaerieTrapSink` for the module
pub sinks: Vec<FaerieTrapSink>,
}
impl FaerieTrapManifest {
/// Create an empty `FaerieTrapManifest`
pub fn new() -> Self {
Self { sinks: Vec::new() }
}
/// Put a `FaerieTrapSink` into manifest
pub fn add_sink(&mut self, sink: FaerieTrapSink) -> &[TrapSite] {
self.sinks.push(sink);
&self.sinks.last().unwrap().sites
}
}

View File

@@ -6,7 +6,6 @@ use crate::FuncId;
use crate::Linkage; use crate::Linkage;
use crate::ModuleNamespace; use crate::ModuleNamespace;
use crate::ModuleResult; use crate::ModuleResult;
use crate::TrapSite;
use core::marker; use core::marker;
use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::isa::TargetIsa;
use cranelift_codegen::Context; use cranelift_codegen::Context;
@@ -15,7 +14,6 @@ use cranelift_codegen::{binemit, ir};
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::boxed::Box; use std::boxed::Box;
use std::string::String; use std::string::String;
use std::vec::Vec;
/// A `Backend` implements the functionality needed to support a `Module`. /// A `Backend` implements the functionality needed to support a `Module`.
/// ///
@@ -79,14 +77,17 @@ where
/// Define a function, producing the function body from the given `Context`. /// Define a function, producing the function body from the given `Context`.
/// ///
/// Functions must be declared before being defined. /// Functions must be declared before being defined.
fn define_function( fn define_function<TS>(
&mut self, &mut self,
id: FuncId, id: FuncId,
name: &str, name: &str,
ctx: &Context, ctx: &Context,
namespace: &ModuleNamespace<Self>, namespace: &ModuleNamespace<Self>,
code_size: u32, code_size: u32,
) -> ModuleResult<(Self::CompiledFunction, &[TrapSite])>; trap_sink: &mut TS,
) -> ModuleResult<Self::CompiledFunction>
where
TS: binemit::TrapSink;
/// Define a function, taking the function body from the given `bytes`. /// Define a function, taking the function body from the given `bytes`.
/// ///
@@ -97,8 +98,7 @@ where
name: &str, name: &str,
bytes: &[u8], bytes: &[u8],
namespace: &ModuleNamespace<Self>, namespace: &ModuleNamespace<Self>,
traps: Vec<TrapSite>, ) -> ModuleResult<Self::CompiledFunction>;
) -> ModuleResult<(Self::CompiledFunction, &[TrapSite])>;
/// Define a zero-initialized data object of the given size. /// Define a zero-initialized data object of the given size.
/// ///

View File

@@ -7,7 +7,6 @@
use super::HashMap; use super::HashMap;
use crate::data_context::DataContext; use crate::data_context::DataContext;
use crate::traps::TrapSite;
use crate::Backend; use crate::Backend;
use cranelift_codegen::binemit::{self, CodeInfo}; use cranelift_codegen::binemit::{self, CodeInfo};
use cranelift_codegen::entity::{entity_impl, PrimaryMap}; use cranelift_codegen::entity::{entity_impl, PrimaryMap};
@@ -363,9 +362,8 @@ where
backend: B, backend: B,
} }
pub struct ModuleCompiledFunction<'a> { pub struct ModuleCompiledFunction {
pub size: binemit::CodeOffset, pub size: binemit::CodeOffset,
pub traps: &'a [TrapSite],
} }
impl<B> Module<B> impl<B> Module<B>
@@ -569,11 +567,15 @@ where
/// Returns the size of the function's code and constant data. /// Returns the size of the function's code and constant data.
/// ///
/// 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.
pub fn define_function( pub fn define_function<TS>(
&mut self, &mut self,
func: FuncId, func: FuncId,
ctx: &mut Context, ctx: &mut Context,
) -> ModuleResult<ModuleCompiledFunction> { trap_sink: &mut TS,
) -> ModuleResult<ModuleCompiledFunction>
where
TS: binemit::TrapSink,
{
info!( info!(
"defining function {}: {}", "defining function {}: {}",
func, func,
@@ -588,7 +590,7 @@ where
return Err(ModuleError::InvalidImportDefinition(info.decl.name.clone())); return Err(ModuleError::InvalidImportDefinition(info.decl.name.clone()));
} }
let (compiled, traps) = self.backend.define_function( let compiled = self.backend.define_function(
func, func,
&info.decl.name, &info.decl.name,
ctx, ctx,
@@ -596,14 +598,12 @@ where
contents: &self.contents, contents: &self.contents,
}, },
total_size, total_size,
trap_sink,
)?; )?;
self.contents.functions[func].compiled = Some(compiled); self.contents.functions[func].compiled = Some(compiled);
self.functions_to_finalize.push(func); self.functions_to_finalize.push(func);
Ok(ModuleCompiledFunction { Ok(ModuleCompiledFunction { size: total_size })
size: total_size,
traps,
})
} }
/// Define a function, taking the function body from the given `bytes`. /// Define a function, taking the function body from the given `bytes`.
@@ -617,7 +617,6 @@ where
&mut self, &mut self,
func: FuncId, func: FuncId,
bytes: &[u8], bytes: &[u8],
traps: Vec<TrapSite>,
) -> ModuleResult<ModuleCompiledFunction> { ) -> ModuleResult<ModuleCompiledFunction> {
info!("defining function {} with bytes", func); info!("defining function {} with bytes", func);
let info = &self.contents.functions[func]; let info = &self.contents.functions[func];
@@ -633,22 +632,18 @@ where
_ => Err(ModuleError::FunctionTooLarge(info.decl.name.clone()))?, _ => Err(ModuleError::FunctionTooLarge(info.decl.name.clone()))?,
}; };
let (compiled, traps) = self.backend.define_function_bytes( let compiled = self.backend.define_function_bytes(
func, func,
&info.decl.name, &info.decl.name,
bytes, bytes,
&ModuleNamespace::<B> { &ModuleNamespace::<B> {
contents: &self.contents, contents: &self.contents,
}, },
traps,
)?; )?;
self.contents.functions[func].compiled = Some(compiled); self.contents.functions[func].compiled = Some(compiled);
self.functions_to_finalize.push(func); self.functions_to_finalize.push(func);
Ok(ModuleCompiledFunction { Ok(ModuleCompiledFunction { size: total_size })
size: total_size,
traps,
})
} }
/// Define a data object, producing the data contents from the given `DataContext`. /// Define a data object, producing the data contents from the given `DataContext`.

View File

@@ -1,15 +1,14 @@
//! Defines `ObjectBackend`. //! Defines `ObjectBackend`.
use crate::traps::ObjectTrapSink;
use cranelift_codegen::binemit::{ use cranelift_codegen::binemit::{
Addend, CodeOffset, NullStackmapSink, NullTrapSink, Reloc, RelocSink, Addend, CodeOffset, NullStackmapSink, Reloc, RelocSink, TrapSink,
}; };
use cranelift_codegen::entity::SecondaryMap; use cranelift_codegen::entity::SecondaryMap;
use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::isa::TargetIsa;
use cranelift_codegen::{self, binemit, ir}; use cranelift_codegen::{self, binemit, ir};
use cranelift_module::{ use cranelift_module::{
Backend, DataContext, DataDescription, DataId, FuncId, Init, Linkage, ModuleNamespace, Backend, DataContext, DataDescription, DataId, FuncId, Init, Linkage, ModuleNamespace,
ModuleResult, TrapSite, ModuleResult,
}; };
use object::write::{ use object::write::{
Object, Relocation, SectionId, StandardSection, Symbol, SymbolId, SymbolSection, Object, Relocation, SectionId, StandardSection, Symbol, SymbolId, SymbolSection,
@@ -17,24 +16,12 @@ use object::write::{
use object::{RelocationEncoding, RelocationKind, SymbolFlags, SymbolKind, SymbolScope}; use object::{RelocationEncoding, RelocationKind, SymbolFlags, SymbolKind, SymbolScope};
use std::collections::HashMap; use std::collections::HashMap;
use std::mem; use std::mem;
use std::ops::IndexMut;
use target_lexicon::{BinaryFormat, PointerWidth}; use target_lexicon::{BinaryFormat, PointerWidth};
#[derive(Debug)]
/// Setting to enable collection of traps. Setting this to `Enabled` in
/// `ObjectBuilder` means that `ObjectProduct` will contains trap sites.
pub enum ObjectTrapCollection {
/// `ObjectProduct::traps` will be empty
Disabled,
/// `ObjectProduct::traps` will contain trap sites
Enabled,
}
/// A builder for `ObjectBackend`. /// A builder for `ObjectBackend`.
pub struct ObjectBuilder { pub struct ObjectBuilder {
isa: Box<dyn TargetIsa>, isa: Box<dyn TargetIsa>,
name: Vec<u8>, name: Vec<u8>,
collect_traps: ObjectTrapCollection,
libcall_names: Box<dyn Fn(ir::LibCall) -> String>, libcall_names: Box<dyn Fn(ir::LibCall) -> String>,
function_alignment: u64, function_alignment: u64,
} }
@@ -43,9 +30,6 @@ impl ObjectBuilder {
/// Create a new `ObjectBuilder` using the given Cranelift target, that /// Create a new `ObjectBuilder` using the given Cranelift target, that
/// can be passed to [`Module::new`](cranelift_module::Module::new). /// can be passed to [`Module::new`](cranelift_module::Module::new).
/// ///
/// `collect_traps` setting determines whether trap information is collected in the
/// `ObjectProduct`.
///
/// The `libcall_names` function provides a way to translate `cranelift_codegen`'s `ir::LibCall` /// The `libcall_names` function provides a way to translate `cranelift_codegen`'s `ir::LibCall`
/// enum to symbols. LibCalls are inserted in the IR as part of the legalization for certain /// enum to symbols. LibCalls are inserted in the IR as part of the legalization for certain
/// floating point instructions, and for stack probes. If you don't know what to use for this /// floating point instructions, and for stack probes. If you don't know what to use for this
@@ -53,13 +37,11 @@ impl ObjectBuilder {
pub fn new<V: Into<Vec<u8>>>( pub fn new<V: Into<Vec<u8>>>(
isa: Box<dyn TargetIsa>, isa: Box<dyn TargetIsa>,
name: V, name: V,
collect_traps: ObjectTrapCollection,
libcall_names: Box<dyn Fn(ir::LibCall) -> String>, libcall_names: Box<dyn Fn(ir::LibCall) -> String>,
) -> Self { ) -> Self {
Self { Self {
isa, isa,
name: name.into(), name: name.into(),
collect_traps,
libcall_names, libcall_names,
function_alignment: 1, function_alignment: 1,
} }
@@ -80,11 +62,9 @@ pub struct ObjectBackend {
object: Object, object: Object,
functions: SecondaryMap<FuncId, Option<SymbolId>>, functions: SecondaryMap<FuncId, Option<SymbolId>>,
data_objects: SecondaryMap<DataId, Option<SymbolId>>, data_objects: SecondaryMap<DataId, Option<SymbolId>>,
traps: SecondaryMap<FuncId, Vec<TrapSite>>,
relocs: Vec<SymbolRelocs>, relocs: Vec<SymbolRelocs>,
libcalls: HashMap<ir::LibCall, SymbolId>, libcalls: HashMap<ir::LibCall, SymbolId>,
libcall_names: Box<dyn Fn(ir::LibCall) -> String>, libcall_names: Box<dyn Fn(ir::LibCall) -> String>,
collect_traps: ObjectTrapCollection,
function_alignment: u64, function_alignment: u64,
} }
@@ -111,11 +91,9 @@ impl Backend for ObjectBackend {
object, object,
functions: SecondaryMap::new(), functions: SecondaryMap::new(),
data_objects: SecondaryMap::new(), data_objects: SecondaryMap::new(),
traps: SecondaryMap::new(),
relocs: Vec::new(), relocs: Vec::new(),
libcalls: HashMap::new(), libcalls: HashMap::new(),
libcall_names: builder.libcall_names, libcall_names: builder.libcall_names,
collect_traps: builder.collect_traps,
function_alignment: builder.function_alignment, function_alignment: builder.function_alignment,
} }
} }
@@ -182,41 +160,31 @@ impl Backend for ObjectBackend {
} }
} }
fn define_function( fn define_function<TS>(
&mut self, &mut self,
func_id: FuncId, func_id: FuncId,
_name: &str, _name: &str,
ctx: &cranelift_codegen::Context, ctx: &cranelift_codegen::Context,
_namespace: &ModuleNamespace<Self>, _namespace: &ModuleNamespace<Self>,
code_size: u32, code_size: u32,
) -> ModuleResult<(ObjectCompiledFunction, &[TrapSite])> { trap_sink: &mut TS,
) -> ModuleResult<ObjectCompiledFunction>
where
TS: TrapSink,
{
let mut code: Vec<u8> = vec![0; code_size as usize]; let mut code: Vec<u8> = vec![0; code_size as usize];
let mut reloc_sink = ObjectRelocSink::new(self.object.format()); let mut reloc_sink = ObjectRelocSink::new(self.object.format());
let mut trap_sink = ObjectTrapSink::default();
let mut stackmap_sink = NullStackmapSink {}; let mut stackmap_sink = NullStackmapSink {};
if let ObjectTrapCollection::Enabled = self.collect_traps {
unsafe { unsafe {
ctx.emit_to_memory( ctx.emit_to_memory(
&*self.isa, &*self.isa,
code.as_mut_ptr(), code.as_mut_ptr(),
&mut reloc_sink, &mut reloc_sink,
&mut trap_sink, trap_sink,
&mut stackmap_sink, &mut stackmap_sink,
) )
}; };
} else {
let mut trap_sink = NullTrapSink {};
unsafe {
ctx.emit_to_memory(
&*self.isa,
code.as_mut_ptr(),
&mut reloc_sink,
&mut trap_sink,
&mut stackmap_sink,
)
};
}
let symbol = self.functions[func_id].unwrap(); let symbol = self.functions[func_id].unwrap();
let section = self.object.section_id(StandardSection::Text); let section = self.object.section_id(StandardSection::Text);
@@ -230,9 +198,7 @@ impl Backend for ObjectBackend {
relocs: reloc_sink.relocs, relocs: reloc_sink.relocs,
}); });
} }
let trapref = self.traps.index_mut(func_id); Ok(ObjectCompiledFunction)
*trapref = trap_sink.sites;
Ok((ObjectCompiledFunction, trapref))
} }
fn define_function_bytes( fn define_function_bytes(
@@ -241,16 +207,13 @@ impl Backend for ObjectBackend {
_name: &str, _name: &str,
bytes: &[u8], bytes: &[u8],
_namespace: &ModuleNamespace<Self>, _namespace: &ModuleNamespace<Self>,
traps: Vec<TrapSite>, ) -> ModuleResult<ObjectCompiledFunction> {
) -> ModuleResult<(ObjectCompiledFunction, &[TrapSite])> {
let symbol = self.functions[func_id].unwrap(); let symbol = self.functions[func_id].unwrap();
let section = self.object.section_id(StandardSection::Text); let section = self.object.section_id(StandardSection::Text);
let _offset = self let _offset = self
.object .object
.add_symbol_data(symbol, section, bytes, self.function_alignment); .add_symbol_data(symbol, section, bytes, self.function_alignment);
let trapref = self.traps.index_mut(func_id); Ok(ObjectCompiledFunction)
*trapref = traps;
Ok((ObjectCompiledFunction, trapref))
} }
fn define_data( fn define_data(
@@ -421,7 +384,6 @@ impl Backend for ObjectBackend {
object: self.object, object: self.object,
functions: self.functions, functions: self.functions,
data_objects: self.data_objects, data_objects: self.data_objects,
traps: self.traps,
} }
} }
} }
@@ -496,8 +458,6 @@ pub struct ObjectProduct {
pub functions: SecondaryMap<FuncId, Option<SymbolId>>, pub functions: SecondaryMap<FuncId, Option<SymbolId>>,
/// Symbol IDs for data objects (both declared and defined). /// Symbol IDs for data objects (both declared and defined).
pub data_objects: SecondaryMap<DataId, Option<SymbolId>>, pub data_objects: SecondaryMap<DataId, Option<SymbolId>>,
/// Trap sites for defined functions.
pub traps: SecondaryMap<FuncId, Vec<TrapSite>>,
} }
impl ObjectProduct { impl ObjectProduct {

View File

@@ -26,10 +26,8 @@
)] )]
mod backend; mod backend;
mod traps;
pub use crate::backend::{ObjectBackend, ObjectBuilder, ObjectProduct, ObjectTrapCollection}; pub use crate::backend::{ObjectBackend, ObjectBuilder, ObjectProduct};
pub use crate::traps::ObjectTrapSink;
/// Version number of this crate. /// Version number of this crate.
pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub const VERSION: &str = env!("CARGO_PKG_VERSION");

View File

@@ -1,22 +0,0 @@
//! Records every `TrapCode` that cranelift outputs during code generation,
//! for every function in the module. This data may be useful at runtime.
use cranelift_codegen::{binemit, ir};
use cranelift_module::TrapSite;
/// Record of the trap sites for a given function
#[derive(Default, Clone)]
pub struct ObjectTrapSink {
/// All trap sites collected in function
pub sites: Vec<TrapSite>,
}
impl binemit::TrapSink for ObjectTrapSink {
fn trap(&mut self, offset: binemit::CodeOffset, srcloc: ir::SourceLoc, code: ir::TrapCode) {
self.sites.push(TrapSite {
offset,
srcloc,
code,
});
}
}

View File

@@ -1,4 +1,5 @@
use cranelift::prelude::*; use cranelift::prelude::*;
use cranelift_codegen::binemit::NullTrapSink;
use cranelift_module::{default_libcall_names, Linkage, Module}; use cranelift_module::{default_libcall_names, Linkage, Module};
use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder}; use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder};
use std::mem; use std::mem;
@@ -38,7 +39,10 @@ fn main() {
bcx.seal_all_blocks(); bcx.seal_all_blocks();
bcx.finalize(); bcx.finalize();
} }
module.define_function(func_a, &mut ctx).unwrap(); let mut trap_sink = NullTrapSink {};
module
.define_function(func_a, &mut ctx, &mut trap_sink)
.unwrap();
module.clear_context(&mut ctx); module.clear_context(&mut ctx);
ctx.func.signature = sig_b; ctx.func.signature = sig_b;
@@ -60,7 +64,9 @@ fn main() {
bcx.seal_all_blocks(); bcx.seal_all_blocks();
bcx.finalize(); bcx.finalize();
} }
module.define_function(func_b, &mut ctx).unwrap(); module
.define_function(func_b, &mut ctx, &mut trap_sink)
.unwrap();
module.clear_context(&mut ctx); module.clear_context(&mut ctx);
// Perform linking. // Perform linking.

View File

@@ -2,13 +2,13 @@
use crate::memory::Memory; use crate::memory::Memory;
use cranelift_codegen::binemit::{ use cranelift_codegen::binemit::{
Addend, CodeOffset, NullTrapSink, Reloc, RelocSink, Stackmap, StackmapSink, Addend, CodeOffset, Reloc, RelocSink, Stackmap, StackmapSink, TrapSink,
}; };
use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::isa::TargetIsa;
use cranelift_codegen::{self, ir, settings}; use cranelift_codegen::{self, ir, settings};
use cranelift_module::{ use cranelift_module::{
Backend, DataContext, DataDescription, DataId, FuncId, Init, Linkage, ModuleNamespace, Backend, DataContext, DataDescription, DataId, FuncId, Init, Linkage, ModuleNamespace,
ModuleResult, TrapSite, ModuleResult,
}; };
use cranelift_native; use cranelift_native;
#[cfg(not(windows))] #[cfg(not(windows))]
@@ -271,14 +271,18 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend {
// Nothing to do. // Nothing to do.
} }
fn define_function( fn define_function<TS>(
&mut self, &mut self,
_id: FuncId, _id: FuncId,
name: &str, name: &str,
ctx: &cranelift_codegen::Context, ctx: &cranelift_codegen::Context,
_namespace: &ModuleNamespace<Self>, _namespace: &ModuleNamespace<Self>,
code_size: u32, code_size: u32,
) -> ModuleResult<(Self::CompiledFunction, &[TrapSite])> { trap_sink: &mut TS,
) -> ModuleResult<Self::CompiledFunction>
where
TS: TrapSink,
{
let size = code_size as usize; let size = code_size as usize;
let ptr = self let ptr = self
.memory .memory
@@ -289,28 +293,22 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend {
self.record_function_for_perf(ptr, size, name); self.record_function_for_perf(ptr, size, name);
let mut reloc_sink = SimpleJITRelocSink::new(); let mut reloc_sink = SimpleJITRelocSink::new();
// Ignore traps for now. For now, frontends should just avoid generating code
// that traps.
let mut trap_sink = NullTrapSink {};
let mut stackmap_sink = SimpleJITStackmapSink::new(); let mut stackmap_sink = SimpleJITStackmapSink::new();
unsafe { unsafe {
ctx.emit_to_memory( ctx.emit_to_memory(
&*self.isa, &*self.isa,
ptr, ptr,
&mut reloc_sink, &mut reloc_sink,
&mut trap_sink, trap_sink,
&mut stackmap_sink, &mut stackmap_sink,
) )
}; };
Ok(( Ok(Self::CompiledFunction {
Self::CompiledFunction {
code: ptr, code: ptr,
size, size,
relocs: reloc_sink.relocs, relocs: reloc_sink.relocs,
}, })
&[],
))
} }
fn define_function_bytes( fn define_function_bytes(
@@ -319,8 +317,7 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend {
name: &str, name: &str,
bytes: &[u8], bytes: &[u8],
_namespace: &ModuleNamespace<Self>, _namespace: &ModuleNamespace<Self>,
_traps: Vec<TrapSite>, ) -> ModuleResult<Self::CompiledFunction> {
) -> ModuleResult<(Self::CompiledFunction, &[TrapSite])> {
let size = bytes.len(); let size = bytes.len();
let ptr = self let ptr = self
.memory .memory
@@ -334,14 +331,11 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend {
ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, size); ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, size);
} }
Ok(( Ok(Self::CompiledFunction {
Self::CompiledFunction {
code: ptr, code: ptr,
size, size,
relocs: vec![], relocs: vec![],
}, })
&[],
))
} }
fn define_data( fn define_data(

View File

@@ -1,3 +1,4 @@
use cranelift_codegen::binemit::NullTrapSink;
use cranelift_codegen::ir::*; use cranelift_codegen::ir::*;
use cranelift_codegen::isa::CallConv; use cranelift_codegen::isa::CallConv;
use cranelift_codegen::{ir::types::I16, Context}; use cranelift_codegen::{ir::types::I16, Context};
@@ -46,7 +47,10 @@ fn define_simple_function(module: &mut Module<SimpleJITBackend>) -> FuncId {
bcx.ins().return_(&[]); bcx.ins().return_(&[]);
} }
module.define_function(func_id, &mut ctx).unwrap(); let mut trap_sink = NullTrapSink {};
module
.define_function(func_id, &mut ctx, &mut trap_sink)
.unwrap();
func_id func_id
} }
@@ -191,7 +195,10 @@ fn libcall_function() {
bcx.ins().return_(&[]); bcx.ins().return_(&[]);
} }
module.define_function(func_id, &mut ctx).unwrap(); let mut trap_sink = NullTrapSink {};
module
.define_function(func_id, &mut ctx, &mut trap_sink)
.unwrap();
module.finalize_definitions(); module.finalize_definitions();
} }