1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
use std::{
    marker::PhantomData,
    sync::atomic::{AtomicU64, Ordering},
};

use crate::Object;

/// The raw invariant pointer, containing just a 64-bit packed FOT entry and offset.
#[repr(transparent)]
pub struct InvPtr<T> {
    raw: u64,
    _pd: PhantomData<T>,
}

impl<T> !Unpin for InvPtr<T> {}

impl<T> Object<T> {
    /// Get a raw pointer into an object given an offset.
    #[inline]
    pub fn raw_lea<P>(&self, off: usize) -> *const P {
        self.slot.raw_lea(off)
    }

    /// Get a raw mutable pointer into an object given an offset.
    #[inline]
    pub fn raw_lea_mut<P>(&self, off: usize) -> *mut P {
        self.slot.raw_lea_mut(off)
    }
}

fn ipoffset(raw: u64) -> u64 {
    raw & 0x0000ffffffffffff
}

fn ipfote(raw: u64) -> u64 {
    (raw & !0x0000ffffffffffff) >> 48
}

impl<Target> InvPtr<Target> {
    /// Read the invariant pointer into its raw parts.
    ///
    /// # Safety
    /// See this crate's base documentation ([Isolation Safety](crate)).
    pub unsafe fn parts_unguarded(&self) -> (usize, u64) {
        let raw = self.raw;
        (ipfote(raw) as usize, ipoffset(raw))
    }

    /// Read the invariant pointer into its raw parts.
    pub fn parts(&mut self) -> (usize, u64) {
        let raw = self.raw;
        (ipfote(raw) as usize, ipoffset(raw))
    }

    /// Construct an InvPtr from an FOT entry and an offset.
    pub fn from_parts(fote: usize, off: u64) -> Self {
        Self {
            raw: (fote << 48) as u64 | (off & 0x0000ffffffffffff),
            _pd: PhantomData,
        }
    }

    /// Check if an invariant pointer is null.
    ///
    /// # Safety
    /// See this crate's base documentation ([Isolation Safety](crate)).
    pub unsafe fn is_null_unguarded(&self) -> bool {
        self.raw == 0
    }

    /// Check if an invariant pointer is null.
    pub fn is_null(&mut self) -> bool {
        self.raw == 0
    }

    /// Construct a null raw pointer.
    pub fn null() -> Self {
        Self {
            raw: 0,
            _pd: PhantomData,
        }
    }

    /// Get a reference to the inner raw 64 bits of the invariant pointer.
    ///
    /// # Safety
    /// See this crate's base documentation ([Isolation Safety](crate)). Additionally, the caller is
    /// expected to maintain the correct semantics of invariant pointers.
    pub unsafe fn raw_inner(&mut self) -> *mut u64 {
        &mut self.raw as *mut u64
    }
}

/// An atomic invariant pointer. Allows reading through an immutable reference without unsafe.
#[repr(transparent)]
pub struct AtomicInvPtr<T> {
    raw: AtomicU64,
    _pd: PhantomData<T>,
}

impl<T> !Unpin for AtomicInvPtr<T> {}

impl<Target> AtomicInvPtr<Target> {
    /// Read the invariant pointer into its raw parts.
    pub fn parts(&self) -> (usize, u64) {
        let raw = self.raw.load(Ordering::SeqCst);
        (ipfote(raw) as usize, ipoffset(raw))
    }

    /// Construct an InvPtr from an FOT entry and an offset.
    pub fn from_parts(fote: usize, off: u64) -> Self {
        Self {
            raw: AtomicU64::new((fote << 48) as u64 | (off & 0x0000ffffffffffff)),
            _pd: PhantomData,
        }
    }

    /// Check if an invariant pointer is null.
    pub fn is_null(&self) -> bool {
        let raw = self.raw.load(Ordering::SeqCst);
        raw == 0
    }

    /// Construct a null raw pointer.
    pub fn null() -> Self {
        Self {
            raw: AtomicU64::new(0),
            _pd: PhantomData,
        }
    }

    /// Get a reference to the inner raw 64 bits of the invariant pointer.
    ///
    /// # Safety
    /// See this crate's base documentation ([Isolation Safety](crate)). Additionally, the caller is
    /// expected to maintain the correct semantics of invariant pointers.
    pub unsafe fn inner(&mut self) -> *mut AtomicU64 {
        &mut self.raw as *mut AtomicU64
    }
}