1 //! User-defined stack maps. 2 //! 3 //! This module provides types allowing users to define stack maps and associate 4 //! them with safepoints. 5 //! 6 //! A **safepoint** is a program point (i.e. CLIF instruction) where it must be 7 //! safe to run GC. Currently all non-tail call instructions are considered 8 //! safepoints. (This does *not* allow, for example, skipping safepoints for 9 //! calls that are statically known not to trigger collections, or to have a 10 //! safepoint on a volatile load to a page that gets protected when it is time 11 //! to GC, triggering a fault that pauses the mutator and lets the collector do 12 //! its work before resuming the mutator. We can lift this restriction in the 13 //! future, if necessary.) 14 //! 15 //! A **stack map** is a description of where to find all the GC-managed values 16 //! that are live at a particular safepoint. Stack maps let the collector find 17 //! on-stack roots. Each stack map is logically a set of offsets into the stack 18 //! frame and the type of value at that associated offset. However, because the 19 //! stack layout isn't defined until much later in the compiler's pipeline, each 20 //! stack map entry instead includes both an `ir::StackSlot` and an offset 21 //! within that slot. 22 //! 23 //! These stack maps are **user-defined** in that it is the CLIF producer's 24 //! responsibility to identify and spill the live GC-managed values and attach 25 //! the associated stack map entries to each safepoint themselves (see 26 //! `cranelift_frontend::Function::declare_needs_stack_map` and 27 //! `cranelift_codegen::ir::DataFlowGraph::append_user_stack_map_entry`). Cranelift 28 //! will not insert spills and record these stack map entries automatically (in 29 //! contrast to the old system and its `r64` values). 30 31 use crate::ir; 32 use cranelift_bitset::CompoundBitSet; 33 use cranelift_entity::PrimaryMap; 34 use smallvec::SmallVec; 35 36 pub(crate) type UserStackMapEntryVec = SmallVec<[UserStackMapEntry; 4]>; 37 38 /// A stack map entry describes a single GC-managed value and its location on 39 /// the stack. 40 /// 41 /// A stack map entry is associated with a particular instruction, and that 42 /// instruction must be a safepoint. The GC-managed value must be stored in the 43 /// described location across this entry's instruction. 44 #[derive(Clone, Debug, PartialEq, Hash)] 45 #[cfg_attr( 46 feature = "enable-serde", 47 derive(serde_derive::Serialize, serde_derive::Deserialize) 48 )] 49 pub struct UserStackMapEntry { 50 /// The type of the value stored in this stack map entry. 51 pub ty: ir::Type, 52 53 /// The stack slot that this stack map entry is within. 54 pub slot: ir::StackSlot, 55 56 /// The offset within the stack slot where this entry's value can be found. 57 pub offset: u32, 58 } 59 60 /// A compiled stack map, describing the location of many GC-managed values. 61 /// 62 /// A stack map is associated with a particular instruction, and that 63 /// instruction is a safepoint. 64 #[derive(Clone, Debug, PartialEq)] 65 #[cfg_attr( 66 feature = "enable-serde", 67 derive(serde_derive::Deserialize, serde_derive::Serialize) 68 )] 69 pub struct UserStackMap { 70 by_type: SmallVec<[(ir::Type, CompoundBitSet); 1]>, 71 } 72 73 impl UserStackMap { 74 /// Coalesce the given entries into a new `UserStackMap`. 75 pub fn new( 76 entries: &[UserStackMapEntry], 77 stack_slot_offsets: &PrimaryMap<ir::StackSlot, u32>, 78 ) -> Self { 79 let mut by_type = SmallVec::<[(ir::Type, CompoundBitSet); 1]>::default(); 80 81 for entry in entries { 82 let offset = stack_slot_offsets[entry.slot] + entry.offset; 83 let offset = usize::try_from(offset).unwrap(); 84 85 // Don't bother trying to avoid an `O(n)` search here: `n` is 86 // basically always one in practice; even if it isn't, there aren't 87 // that many different CLIF types. 88 let index = by_type 89 .iter() 90 .position(|(ty, _)| *ty == entry.ty) 91 .unwrap_or_else(|| { 92 by_type.push((entry.ty, CompoundBitSet::with_capacity(offset + 1))); 93 by_type.len() - 1 94 }); 95 96 by_type[index].1.insert(offset); 97 } 98 99 UserStackMap { by_type } 100 } 101 } 102