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,15 +1,14 @@
//! Defines `ObjectBackend`.
use crate::traps::ObjectTrapSink;
use cranelift_codegen::binemit::{
Addend, CodeOffset, NullStackmapSink, NullTrapSink, Reloc, RelocSink,
Addend, CodeOffset, NullStackmapSink, Reloc, RelocSink, TrapSink,
};
use cranelift_codegen::entity::SecondaryMap;
use cranelift_codegen::isa::TargetIsa;
use cranelift_codegen::{self, binemit, ir};
use cranelift_module::{
Backend, DataContext, DataDescription, DataId, FuncId, Init, Linkage, ModuleNamespace,
ModuleResult, TrapSite,
ModuleResult,
};
use object::write::{
Object, Relocation, SectionId, StandardSection, Symbol, SymbolId, SymbolSection,
@@ -17,24 +16,12 @@ use object::write::{
use object::{RelocationEncoding, RelocationKind, SymbolFlags, SymbolKind, SymbolScope};
use std::collections::HashMap;
use std::mem;
use std::ops::IndexMut;
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`.
pub struct ObjectBuilder {
isa: Box<dyn TargetIsa>,
name: Vec<u8>,
collect_traps: ObjectTrapCollection,
libcall_names: Box<dyn Fn(ir::LibCall) -> String>,
function_alignment: u64,
}
@@ -43,9 +30,6 @@ impl ObjectBuilder {
/// Create a new `ObjectBuilder` using the given Cranelift target, that
/// 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`
/// 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
@@ -53,13 +37,11 @@ impl ObjectBuilder {
pub fn new<V: Into<Vec<u8>>>(
isa: Box<dyn TargetIsa>,
name: V,
collect_traps: ObjectTrapCollection,
libcall_names: Box<dyn Fn(ir::LibCall) -> String>,
) -> Self {
Self {
isa,
name: name.into(),
collect_traps,
libcall_names,
function_alignment: 1,
}
@@ -80,11 +62,9 @@ pub struct ObjectBackend {
object: Object,
functions: SecondaryMap<FuncId, Option<SymbolId>>,
data_objects: SecondaryMap<DataId, Option<SymbolId>>,
traps: SecondaryMap<FuncId, Vec<TrapSite>>,
relocs: Vec<SymbolRelocs>,
libcalls: HashMap<ir::LibCall, SymbolId>,
libcall_names: Box<dyn Fn(ir::LibCall) -> String>,
collect_traps: ObjectTrapCollection,
function_alignment: u64,
}
@@ -111,11 +91,9 @@ impl Backend for ObjectBackend {
object,
functions: SecondaryMap::new(),
data_objects: SecondaryMap::new(),
traps: SecondaryMap::new(),
relocs: Vec::new(),
libcalls: HashMap::new(),
libcall_names: builder.libcall_names,
collect_traps: builder.collect_traps,
function_alignment: builder.function_alignment,
}
}
@@ -182,41 +160,31 @@ impl Backend for ObjectBackend {
}
}
fn define_function(
fn define_function<TS>(
&mut self,
func_id: FuncId,
_name: &str,
ctx: &cranelift_codegen::Context,
_namespace: &ModuleNamespace<Self>,
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 reloc_sink = ObjectRelocSink::new(self.object.format());
let mut trap_sink = ObjectTrapSink::default();
let mut stackmap_sink = NullStackmapSink {};
if let ObjectTrapCollection::Enabled = self.collect_traps {
unsafe {
ctx.emit_to_memory(
&*self.isa,
code.as_mut_ptr(),
&mut reloc_sink,
&mut trap_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,
)
};
}
unsafe {
ctx.emit_to_memory(
&*self.isa,
code.as_mut_ptr(),
&mut reloc_sink,
trap_sink,
&mut stackmap_sink,
)
};
let symbol = self.functions[func_id].unwrap();
let section = self.object.section_id(StandardSection::Text);
@@ -230,9 +198,7 @@ impl Backend for ObjectBackend {
relocs: reloc_sink.relocs,
});
}
let trapref = self.traps.index_mut(func_id);
*trapref = trap_sink.sites;
Ok((ObjectCompiledFunction, trapref))
Ok(ObjectCompiledFunction)
}
fn define_function_bytes(
@@ -241,16 +207,13 @@ impl Backend for ObjectBackend {
_name: &str,
bytes: &[u8],
_namespace: &ModuleNamespace<Self>,
traps: Vec<TrapSite>,
) -> ModuleResult<(ObjectCompiledFunction, &[TrapSite])> {
) -> ModuleResult<ObjectCompiledFunction> {
let symbol = self.functions[func_id].unwrap();
let section = self.object.section_id(StandardSection::Text);
let _offset = self
.object
.add_symbol_data(symbol, section, bytes, self.function_alignment);
let trapref = self.traps.index_mut(func_id);
*trapref = traps;
Ok((ObjectCompiledFunction, trapref))
Ok(ObjectCompiledFunction)
}
fn define_data(
@@ -421,7 +384,6 @@ impl Backend for ObjectBackend {
object: self.object,
functions: self.functions,
data_objects: self.data_objects,
traps: self.traps,
}
}
}
@@ -496,8 +458,6 @@ pub struct ObjectProduct {
pub functions: SecondaryMap<FuncId, Option<SymbolId>>,
/// Symbol IDs for data objects (both declared and defined).
pub data_objects: SecondaryMap<DataId, Option<SymbolId>>,
/// Trap sites for defined functions.
pub traps: SecondaryMap<FuncId, Vec<TrapSite>>,
}
impl ObjectProduct {