miri/borrow_tracker/stacked_borrows/
item.rs

1use std::fmt;
2
3use crate::borrow_tracker::BorTag;
4
5/// An item in the per-location borrow stack.
6#[derive(Copy, Clone, Hash, PartialEq, Eq)]
7pub struct Item(u64);
8
9// An Item contains 3 bitfields:
10// * Bits 0-61 store a BorTag.
11// * Bits 61-63 store a Permission.
12// * Bit 64 stores a flag which indicates if we might have a protector.
13//   This is purely an optimization: if the bit is set, the tag *might* be
14//   in `protected_tags`, but if the bit is not set then the tag is definitely
15//   not in `protected_tags`.
16const TAG_MASK: u64 = u64::MAX >> 3;
17const PERM_MASK: u64 = 0x3 << 61;
18const PROTECTED_MASK: u64 = 0x1 << 63;
19
20const PERM_SHIFT: u64 = 61;
21const PROTECTED_SHIFT: u64 = 63;
22
23impl Item {
24    pub fn new(tag: BorTag, perm: Permission, protected: bool) -> Self {
25        assert!(tag.get() <= TAG_MASK);
26        let packed_tag = tag.get();
27        let packed_perm = perm.to_bits() << PERM_SHIFT;
28        let packed_protected = u64::from(protected) << PROTECTED_SHIFT;
29
30        let new = Self(packed_tag | packed_perm | packed_protected);
31
32        debug_assert!(new.tag() == tag);
33        debug_assert!(new.perm() == perm);
34        debug_assert!(new.protected() == protected);
35
36        new
37    }
38
39    /// The pointers the permission is granted to.
40    pub fn tag(self) -> BorTag {
41        BorTag::new(self.0 & TAG_MASK).unwrap()
42    }
43
44    /// The permission this item grants.
45    pub fn perm(self) -> Permission {
46        Permission::from_bits((self.0 & PERM_MASK) >> PERM_SHIFT)
47    }
48
49    /// Whether or not there is a protector for this tag
50    pub fn protected(self) -> bool {
51        self.0 & PROTECTED_MASK > 0
52    }
53
54    /// Set the Permission stored in this Item
55    pub fn set_permission(&mut self, perm: Permission) {
56        // Clear the current set permission
57        self.0 &= !PERM_MASK;
58        // Write Permission::Disabled to the Permission bits
59        self.0 |= perm.to_bits() << PERM_SHIFT;
60    }
61}
62
63impl fmt::Debug for Item {
64    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65        write!(f, "[{:?} for {:?}]", self.perm(), self.tag())
66    }
67}
68
69/// Indicates which permission is granted (by this item to some pointers)
70#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
71pub enum Permission {
72    /// Grants unique mutable access.
73    Unique,
74    /// Grants shared mutable access.
75    SharedReadWrite,
76    /// Grants shared read-only access.
77    SharedReadOnly,
78    /// Grants no access, but separates two groups of SharedReadWrite so they are not
79    /// all considered mutually compatible.
80    Disabled,
81}
82
83impl Permission {
84    const UNIQUE: u64 = 0;
85    const SHARED_READ_WRITE: u64 = 1;
86    const SHARED_READ_ONLY: u64 = 2;
87    const DISABLED: u64 = 3;
88
89    fn to_bits(self) -> u64 {
90        match self {
91            Permission::Unique => Self::UNIQUE,
92            Permission::SharedReadWrite => Self::SHARED_READ_WRITE,
93            Permission::SharedReadOnly => Self::SHARED_READ_ONLY,
94            Permission::Disabled => Self::DISABLED,
95        }
96    }
97
98    fn from_bits(perm: u64) -> Self {
99        match perm {
100            Self::UNIQUE => Permission::Unique,
101            Self::SHARED_READ_WRITE => Permission::SharedReadWrite,
102            Self::SHARED_READ_ONLY => Permission::SharedReadOnly,
103            Self::DISABLED => Permission::Disabled,
104            _ => unreachable!(),
105        }
106    }
107}