twizzler/ptr/
invariant.rs

1use std::marker::PhantomData;
2
3use twizzler_abi::object::MAX_SIZE;
4use twizzler_rt_abi::{
5    error::TwzError,
6    object::{MapFlags, ObjectHandle},
7};
8
9use super::{GlobalPtr, Ref, RefMut};
10use crate::{
11    marker::{Invariant, PhantomStoreEffect},
12    object::{FotEntry, RawObject},
13};
14
15#[repr(C)]
16#[derive(Debug, PartialEq, PartialOrd, Ord, Eq)]
17pub struct InvPtr<T: Invariant> {
18    value: u64,
19    _pse: PhantomStoreEffect,
20    _pd: PhantomData<*const T>,
21}
22
23unsafe impl<T: Invariant> Invariant for InvPtr<T> {}
24
25impl<T: Invariant> InvPtr<T> {
26    fn get_this(this: *const Self) -> ObjectHandle {
27        twizzler_rt_abi::object::twz_rt_get_object_handle(this.cast()).unwrap()
28    }
29
30    pub fn global(&self) -> GlobalPtr<T> {
31        let fote = self.fot_index();
32        let obj = Self::get_this(self);
33        if fote == 0 {
34            return GlobalPtr::new(obj.id(), self.offset());
35        }
36        let re = twizzler_rt_abi::object::twz_rt_resolve_fot(&obj, fote, MAX_SIZE, MapFlags::READ)
37            .unwrap();
38        GlobalPtr::new(re.id(), self.offset())
39    }
40
41    #[inline(always)]
42    fn local_resolve(&self) -> *mut T {
43        let this = self as *const Self as *mut Self;
44        this.map_addr(|addr| (addr & !(MAX_SIZE - 1)) + self.offset() as usize)
45            .cast()
46    }
47
48    #[inline]
49    pub unsafe fn resolve(&self) -> Ref<'_, T> {
50        if core::intrinsics::likely(self.is_local()) {
51            return Ref::from_ptr(self.local_resolve());
52        }
53        let res = self
54            .slow_resolve(MapFlags::READ | MapFlags::INDIRECT)
55            .expect("failed to resolve ptr");
56        if let Some(re) = res.1 {
57            Ref::from_handle(re, res.0)
58        } else {
59            Ref::from_ptr(res.0)
60        }
61    }
62
63    #[inline]
64    pub unsafe fn resolve_mut(&self) -> RefMut<'_, T> {
65        if core::intrinsics::likely(self.is_local()) {
66            return RefMut::from_ptr(self.local_resolve());
67        }
68        let res = self
69            .slow_resolve(MapFlags::WRITE | MapFlags::READ | MapFlags::PERSIST)
70            .expect("failed to resolve ptr");
71        if let Some(re) = res.1 {
72            RefMut::from_handle(re, res.0)
73        } else {
74            RefMut::from_ptr(res.0)
75        }
76    }
77
78    #[inline(never)]
79    unsafe fn slow_resolve(
80        &self,
81        flags: MapFlags,
82    ) -> Result<(*mut T, Option<ObjectHandle>), TwzError> {
83        let fote = self.fot_index();
84        let res: *mut u8 = twizzler_rt_abi::object::twz_rt_resolve_fot_local(
85            self as *const Self as *mut u8,
86            fote,
87            MAX_SIZE,
88            flags,
89        );
90        if !res.is_null() {
91            return Ok((res.add(self.offset() as usize).cast(), None));
92        }
93
94        let obj = Self::get_this(self);
95        let re = twizzler_rt_abi::object::twz_rt_resolve_fot(&obj, fote, MAX_SIZE, flags).unwrap();
96        let ptr = re
97            .lea_mut(self.offset() as usize, size_of::<T>())
98            .unwrap()
99            .cast();
100        Ok((ptr, Some(re)))
101    }
102
103    pub fn null() -> Self {
104        Self::from_raw_parts(0, 0)
105    }
106
107    pub fn is_null(&self) -> bool {
108        self.offset() == 0
109    }
110
111    pub fn from_raw_parts(idx: u32, offset: u64) -> Self {
112        Self {
113            value: ((idx as u64) << 48) | offset,
114            _pse: PhantomStoreEffect,
115            _pd: PhantomData,
116        }
117    }
118
119    pub fn set(&mut self, gp: impl Into<GlobalPtr<T>>) -> crate::Result<()> {
120        let tx = Self::get_this(self);
121        *self = Self::new(tx, gp)?;
122        Ok(())
123    }
124
125    #[inline(always)]
126    pub fn fot_index(&self) -> u64 {
127        self.value >> 48
128    }
129
130    #[inline(always)]
131    pub fn is_local(&self) -> bool {
132        self.fot_index() == 0
133    }
134
135    #[inline(always)]
136    pub fn offset(&self) -> u64 {
137        self.value & ((1 << 48) - 1)
138    }
139
140    #[inline]
141    pub fn raw(&self) -> u64 {
142        self.value
143    }
144
145    pub fn new(tx: impl AsRef<ObjectHandle>, gp: impl Into<GlobalPtr<T>>) -> crate::Result<Self> {
146        let gp = gp.into();
147        let tx = tx.as_ref();
148        if gp.id() == tx.id() {
149            return Ok(Self::from_raw_parts(0, gp.offset()));
150        }
151        let fote: FotEntry = gp.into();
152        let fote =
153            twizzler_rt_abi::object::twz_rt_insert_fot(&tx, (&fote as *const FotEntry).cast())?;
154        Ok(Self::from_raw_parts(fote, gp.offset()))
155    }
156}