cell_gc/
ptr.rs

1//! Non-pinning pointers into the GC heap.
2
3use pages::{PAGE_ALIGN, TypedPage};
4use std::fmt;
5use std::marker::PhantomData;
6use std::mem;
7
8/// A pointer to some `T` in the GC heap.
9///
10/// # Safety
11///
12/// A `Pointer<T>` is a small step up in safety from a raw pointer. A valid
13/// `Pointer<T>` instance is a guarantee that:
14///
15/// * The pointer points into the GC heap, within a GC-allocated page, and not
16/// on top of the `PageHeader`.
17///
18/// * The pointer has the alignment required by the type and GC.
19///
20/// Note that `Pointer<T>` does **not** pin its referent like `GcRef<T>`
21/// does. Therefore, a `Pointer<T>` can still easily be made to dangle or point
22/// at uninitialized memory! The `Pointer<T>` type is not for general use (use
23/// `GcRef<T>` for that instead), only for GC internals. We have to make it
24/// `pub` so that `#[derive(IntoHeap)]` can generate code that uses it, but no
25/// one else should!
26#[derive(Hash, PartialOrd, Ord)]
27pub struct Pointer<T> {
28    ptr: UntypedPointer,
29    phantom: PhantomData<*const T>,
30}
31
32impl<T> Pointer<T> {
33    /// Construct a new `Pointer<T>` from a raw `*const T`.
34    ///
35    /// # Safety
36    ///
37    /// It is the responsibility of callers to ensure that the guarantees
38    /// mentioned above hold true.
39    ///
40    /// # Panics
41    ///
42    /// Panics if the pointer is not aligned properly, or if it would clobber
43    /// the GC's internal `PageHeader`.
44    #[inline]
45    pub unsafe fn new(ptr: *const T) -> Pointer<T> {
46        assert_eq!(
47            ptr as usize & (mem::align_of::<T>() - 1),
48            0,
49            "heap pointers respect T's alignment"
50        );
51        assert!(
52            {
53                let ptr = ptr as usize;
54                let page = ptr & !(PAGE_ALIGN - 1);
55                let allocs = page + TypedPage::<T>::first_allocation_offset();
56                ptr >= allocs
57            },
58            "heap pointers shouldn't clobber the PageHeader"
59        );
60        Pointer {
61            ptr: UntypedPointer::new(ptr as *const ()),
62            phantom: PhantomData,
63        }
64    }
65
66    /// Is this pointer null?
67    #[inline]
68    pub fn is_null(&self) -> bool {
69        self.ptr.is_null()
70    }
71
72    /// Get a reference to the pointed-to `T` instance.
73    ///
74    /// # Safety
75    ///
76    /// If a GC happens and reclaims the referent while the returned reference
77    /// is in use, it will result in use-after-free.
78    ///
79    /// If this pointer doesn't point at a valid `T` instance, then all hell
80    /// will break loose.
81    ///
82    /// # Panics
83    ///
84    /// Panics if the pointer is null.
85    #[inline]
86    pub unsafe fn as_ref(&self) -> &T {
87        assert!(!self.is_null());
88        &*self.as_raw()
89    }
90
91    /// Get the underlying raw pointer.
92    #[inline]
93    pub fn as_raw(&self) -> *const T {
94        self.ptr.as_void() as *const T
95    }
96
97    /// Get the underlying raw pointer as a `*const ()`.
98    #[inline]
99    pub fn as_void(&self) -> *const () {
100        self.ptr.as_void()
101    }
102
103    /// Get the underlying raw pointer as a `usize`.
104    #[inline]
105    pub fn as_usize(&self) -> usize {
106        self.ptr.as_usize()
107    }
108}
109
110impl<T> fmt::Debug for Pointer<T> {
111    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112        write!(f, "Pointer {{ {:p} }}", self.ptr.as_void())
113    }
114}
115
116impl<T> Clone for Pointer<T> {
117    fn clone(&self) -> Pointer<T> {
118        *self
119    }
120}
121
122impl<T> Copy for Pointer<T> {}
123
124impl<T> PartialEq for Pointer<T> {
125    fn eq(&self, other: &Pointer<T>) -> bool {
126        self.ptr == other.ptr
127    }
128}
129
130impl<T> Eq for Pointer<T> {}
131
132impl<T> From<Pointer<T>> for UntypedPointer {
133    fn from(p: Pointer<T>) -> UntypedPointer {
134        p.ptr
135    }
136}
137
138impl<T> From<Pointer<T>> for usize {
139    fn from(p: Pointer<T>) -> usize {
140        p.ptr.as_void() as usize
141    }
142}
143
144/// Similar to `Pointer<T>` but provides no guarantees other than that it points
145/// to some allocation inside the GC heap, and has the minimal GC-required
146/// alignment.
147///
148/// # Safety
149///
150/// See `Pointer<T>`.
151///
152// TODO: The pointer should probably be wrapped in `Option<Shared<...>>` once
153// `Shared` and `NonZero` are stabilized.
154#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
155pub struct UntypedPointer(*const ());
156
157impl UntypedPointer {
158    #[inline]
159    unsafe fn new(ptr: *const ()) -> UntypedPointer {
160        assert_eq!(
161            ptr as usize & (mem::size_of::<usize>() - 1),
162            0,
163            "All GC heap pointers are at least word-aligned"
164        );
165        assert!(
166            {
167                let ptr = ptr as usize;
168                let page = ptr & !(PAGE_ALIGN - 1);
169                let allocs = page + TypedPage::<usize>::first_allocation_offset();
170                ptr >= allocs
171            },
172            "heap pointers shouldn't clobber the PageHeader"
173        );
174        UntypedPointer(ptr)
175    }
176
177    /// Convert this `UntypedPointer` into a `Pointer<T>`.
178    ///
179    /// # Safety
180    ///
181    /// You had better be damn sure that this pointer points at a `T`
182    /// instance. See also the `Pointer<T>` safety rules and its `new` method's
183    /// safety rules.
184    #[inline]
185    pub unsafe fn as_typed_ptr<T>(&self) -> Pointer<T> {
186        Pointer::new(self.0 as *const T)
187    }
188
189    /// Is this pointer null?
190    #[inline]
191    pub fn is_null(&self) -> bool {
192        self.0.is_null()
193    }
194
195    /// Get the underlying raw pointer.
196    #[inline]
197    pub fn as_void(&self) -> *const () {
198        self.0
199    }
200
201    /// Get the underlying raw pointer as a `usize`.
202    #[inline]
203    pub fn as_usize(&self) -> usize {
204        self.0 as usize
205    }
206}