Struct cranelift_codegen::MachBuffer

source ·
pub struct MachBuffer<I: VCodeInst> { /* private fields */ }
Expand description

A buffer of output to be produced, fixed up, and then emitted to a CodeSink in bulk.

This struct uses SmallVecs to support small-ish function bodies without any heap allocation. As such, it will be several kilobytes large. This is likely fine as long as it is stack-allocated for function emission then thrown away; but beware if many buffer objects are retained persistently.

Implementations§

source§

impl<I: VCodeInst> MachBuffer<I>

source

pub fn new() -> MachBuffer<I>

Create a new section, known to start at start_offset and with a size limited to length_limit.

source

pub fn cur_offset(&self) -> CodeOffset

Current offset from start of buffer.

source

pub fn put1(&mut self, value: u8)

Add a byte.

source

pub fn put2(&mut self, value: u16)

Add 2 bytes.

source

pub fn put4(&mut self, value: u32)

Add 4 bytes.

source

pub fn put8(&mut self, value: u64)

Add 8 bytes.

source

pub fn put_data(&mut self, data: &[u8])

Add a slice of bytes.

source

pub fn get_appended_space(&mut self, len: usize) -> &mut [u8]

Reserve appended space and return a mutable slice referring to it.

source

pub fn align_to(&mut self, align_to: CodeOffset)

Align up to the given alignment.

source

pub fn start_patchable(&mut self) -> OpenPatchRegion

Begin a region of patchable code. There is one requirement for the code that is emitted: It must not introduce any instructions that could be chomped (branches are an example of this). In other words, you must not call MachBuffer::add_cond_branch or MachBuffer::add_uncond_branch between calls to this method and MachBuffer::end_patchable.

source

pub fn end_patchable(&mut self, open: OpenPatchRegion) -> PatchRegion

End a region of patchable code, yielding a PatchRegion value that can be consumed later to produce a one-off mutable slice to the associated region of the data buffer.

source

pub fn get_label(&mut self) -> MachLabel

Allocate a Label to refer to some offset. May not be bound to a fixed offset yet.

source

pub fn reserve_labels_for_blocks(&mut self, blocks: usize)

Reserve the first N MachLabels for blocks.

source

pub fn register_constants(&mut self, constants: &VCodeConstants)

Registers metadata in this MachBuffer about the constants provided.

This will record the size/alignment of all constants which will prepare them for emission later on.

source

pub fn register_constant( &mut self, constant: &VCodeConstant, data: &VCodeConstantData, )

Similar to MachBuffer::register_constants but registers a single constant metadata. This function is useful in situations where not all constants are known at the time of emission.

source

pub fn get_label_for_constant(&mut self, constant: VCodeConstant) -> MachLabel

Returns a label that can be used to refer to the constant provided.

This will automatically defer a new constant to be emitted for constant if it has not been previously emitted. Note that this function may return a different label for the same constant at different points in time. The label is valid to use only from the current location; the MachBuffer takes care to emit the same constant multiple times if needed so the constant is always in range.

source

pub fn bind_label(&mut self, label: MachLabel, ctrl_plane: &mut ControlPlane)

Bind a label to the current offset. A label can only be bound once.

source

pub fn use_label_at_offset( &mut self, offset: CodeOffset, label: MachLabel, kind: I::LabelUse, )

Emit a reference to the given label with the given reference type (i.e., branch-instruction format) at the current offset. This is like a relocation, but handled internally.

This can be called before the branch is actually emitted; fixups will not happen until an island is emitted or the buffer is finished.

source

pub fn add_uncond_branch( &mut self, start: CodeOffset, end: CodeOffset, target: MachLabel, )

Inform the buffer of an unconditional branch at the given offset, targeting the given label. May be used to optimize branches. The last added label-use must correspond to this branch. This must be called when the current offset is equal to start; i.e., before actually emitting the branch. This implies that for a branch that uses a label and is eligible for optimizations by the MachBuffer, the proper sequence is:

  • Call use_label_at_offset() to emit the fixup record.
  • Call add_uncond_branch() to make note of the branch.
  • Emit the bytes for the branch’s machine code.

Additional requirement: no labels may be bound between start and end (exclusive on both ends).

source

pub fn add_cond_branch( &mut self, start: CodeOffset, end: CodeOffset, target: MachLabel, inverted: &[u8], )

Inform the buffer of a conditional branch at the given offset, targeting the given label. May be used to optimize branches. The last added label-use must correspond to this branch.

Additional requirement: no labels may be bound between start and end (exclusive on both ends).

source

pub fn optimize_branches(&mut self, ctrl_plane: &mut ControlPlane)

Performs various optimizations on branches pointing at the current label.

source

pub fn defer_trap(&mut self, code: TrapCode) -> MachLabel

Emit a trap at some point in the future with the specified code and stack map.

This function returns a MachLabel which will be the future address of the trap. Jumps should refer to this label, likely by using the MachBuffer::use_label_at_offset method, to get a relocation patched in once the address of the trap is known.

This will batch all traps into the end of the function.

source

pub fn island_needed(&self, distance: CodeOffset) -> bool

Is an island needed within the next N bytes?

source

pub fn emit_island( &mut self, distance: CodeOffset, ctrl_plane: &mut ControlPlane, )

Emit all pending constants and required pending veneers.

Should only be called if island_needed() returns true, i.e., if we actually reach a deadline. It’s not necessarily a problem to do so otherwise but it may result in unnecessary work during emission.

source

pub fn finish( self, constants: &VCodeConstants, ctrl_plane: &mut ControlPlane, ) -> MachBufferFinalized<Stencil>

Finish any deferred emissions and/or fixups.

source

pub fn add_reloc_at_offset<T: Into<RelocTarget> + Clone>( &mut self, offset: CodeOffset, kind: Reloc, target: &T, addend: Addend, )

Add an external relocation at the given offset from current offset.

source

pub fn add_reloc<T: Into<RelocTarget> + Clone>( &mut self, kind: Reloc, target: &T, addend: Addend, )

Add an external relocation at the current offset.

source

pub fn add_trap(&mut self, code: TrapCode)

Add a trap record at the current offset.

source

pub fn add_call_site(&mut self, opcode: Opcode)

Add a call-site record at the current offset.

source

pub fn add_unwind(&mut self, unwind: UnwindInst)

Add an unwind record at the current offset.

source

pub fn start_srcloc(&mut self, loc: RelSourceLoc) -> (CodeOffset, RelSourceLoc)

Set the SourceLoc for code from this offset until the offset at the next call to end_srcloc(). Returns the current CodeOffset and RelSourceLoc.

source

pub fn end_srcloc(&mut self)

Mark the end of the SourceLoc segment started at the last start_srcloc() call.

source

pub fn add_stack_map(&mut self, extent: StackMapExtent, stack_map: StackMap)

Add stack map metadata for this program point: a set of stack offsets (from SP upward) that contain live references.

source

pub fn push_user_stack_map( &mut self, emit_state: &I::State, return_addr: CodeOffset, stack_map: UserStackMap, )

Push a user stack map onto this buffer.

The stack map is associated with the given return_addr code offset. This must be the PC for the instruction just after this stack map’s associated instruction. For example in the sequence call $foo; add r8, rax, the return_addr must be the offset of the start of the add instruction.

Stack maps must be pushed in sorted return_addr order.

Trait Implementations§

source§

impl ByteSink for MachBuffer<Inst>

source§

fn put1(&mut self, value: u8)

Add 1 byte to the code section.
source§

fn put2(&mut self, value: u16)

Add 2 bytes to the code section.
source§

fn put4(&mut self, value: u32)

Add 4 bytes to the code section.
source§

fn put8(&mut self, value: u64)

Add 8 bytes to the code section.

Auto Trait Implementations§

§

impl<I> Freeze for MachBuffer<I>
where <I as MachInst>::LabelUse: Freeze,

§

impl<I> RefUnwindSafe for MachBuffer<I>

§

impl<I> Send for MachBuffer<I>
where <I as MachInst>::LabelUse: Send,

§

impl<I> Sync for MachBuffer<I>
where <I as MachInst>::LabelUse: Sync,

§

impl<I> Unpin for MachBuffer<I>
where <I as MachInst>::LabelUse: Unpin,

§

impl<I> UnwindSafe for MachBuffer<I>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.