rune/core/gc/
heap.rs
1use super::{GcState, Trace};
2use std::{
3 alloc::Layout,
4 cell::{Cell, UnsafeCell},
5 fmt,
6 mem::ManuallyDrop,
7 ops::{Deref, DerefMut},
8 ptr::NonNull,
9};
10
11union GcHeader {
12 header: ManuallyDrop<HeaderData>,
13 fwd_ptr: NonNull<u8>,
14}
15
16unsafe impl Send for GcHeader {}
17
18impl GcHeader {
19 const fn new(marked: bool) -> Self {
20 GcHeader { header: ManuallyDrop::new(HeaderData::new(marked)) }
21 }
22
23 fn is_present(&self) -> bool {
24 unsafe { self.header.is_present == HeaderData::PRESENT }
25 }
26
27 fn get_header(&self) -> Result<&HeaderData, NonNull<u8>> {
28 if self.is_present() {
29 Ok(unsafe { &*self.header })
30 } else {
31 Err(unsafe { self.fwd_ptr })
32 }
33 }
34}
35
36impl fmt::Debug for GcHeader {
37 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38 match self.get_header() {
39 Ok(header) => write!(f, "GcHeader {{ header: {header:?} }}"),
40 Err(ptr) => write!(f, "GcHeader {{ fwd_ptr: {ptr:?} }}"),
41 }
42 }
43}
44
45#[repr(C, align(8))]
51#[derive(Debug)]
52struct HeaderData {
53 is_present: u8,
54 marked: Cell<bool>,
55}
56
57impl HeaderData {
58 const PRESENT: u8 = 1;
59 const fn new(marked: bool) -> Self {
60 Self { is_present: Self::PRESENT, marked: Cell::new(marked) }
61 }
62}
63
64#[repr(C)]
66#[derive(Debug)]
67pub(crate) struct GcHeap<T: ?Sized> {
68 header: UnsafeCell<GcHeader>,
69 data: T,
70}
71
72unsafe impl<T: Sync> Sync for GcHeap<T> {}
73
74impl<T> GcHeap<T> {
75 pub(in crate::core) const fn new(data: T, constant: bool) -> Self {
76 Self {
77 header: UnsafeCell::new(GcHeader::new(constant)),
79 data,
80 }
81 }
82
83 pub(in crate::core) const fn new_pure(data: T) -> Self {
87 Self::new(data, true)
88 }
89
90 fn header(&self) -> &GcHeader {
91 unsafe { &*self.header.get() }
92 }
93
94 pub(in crate::core) fn forward(&self, fwd_ptr: NonNull<u8>) {
95 let header = unsafe { &mut *self.header.get() };
96 header.fwd_ptr = fwd_ptr;
97 }
98
99 pub(in crate::core) fn allocation_state(&self) -> AllocState {
100 match self.header().get_header() {
101 Ok(header) => {
102 if header.marked.get() {
103 AllocState::Global
104 } else {
105 AllocState::Unmoved
106 }
107 }
108 Err(fwd) => AllocState::Forwarded(fwd),
109 }
110 }
111
112 fn is_marked(&self) -> bool {
113 self.header().get_header().unwrap().marked.get()
114 }
115}
116
117pub(in crate::core) enum AllocState {
118 Forwarded(NonNull<u8>),
119 Global,
120 Unmoved,
121}
122
123pub(in crate::core) trait GcMoveable {
127 type Value;
128 fn move_value(&self, _to_space: &bumpalo::Bump) -> Option<(Self::Value, bool)> {
129 None
130 }
131}
132
133impl<'a, T: GcMoveable<Value = NonNull<T>>> GcMoveable for &'a T {
134 type Value = &'a T;
135
136 fn move_value(&self, to_space: &bumpalo::Bump) -> Option<(Self::Value, bool)> {
137 let val = (*self).move_value(to_space);
138 val.map(|(ptr, moved)| (unsafe { ptr.as_ref() }, moved))
139 }
140}
141
142#[macro_export]
143macro_rules! derive_GcMoveable {
144 ($name:ident) => {
145 impl $crate::core::gc::GcMoveable for $name {
146 type Value = std::ptr::NonNull<Self>;
147
148 fn move_value(&self, to_space: &bumpalo::Bump) -> Option<(Self::Value, bool)> {
149 match self.0.move_value(to_space) {
150 Some((ptr, moved)) => Some((ptr.cast::<Self>(), moved)),
151 None => None,
152 }
153 }
154 }
155 };
156}
157
158impl<T> GcMoveable for GcHeap<T> {
159 type Value = NonNull<Self>;
160
161 fn move_value(&self, to_space: &bumpalo::Bump) -> Option<(Self::Value, bool)> {
162 use std::ptr;
163 match self.header().get_header() {
164 Ok(header) => {
165 if header.marked.get() {
166 return None;
168 }
169 let layout = Layout::for_value(self);
171 let to_ptr = to_space.alloc_layout(layout);
172 unsafe {
173 let src = ptr::from_ref(self);
174 let dst = to_ptr.cast::<Self>().as_ptr();
175 ptr::copy_nonoverlapping(src, dst, 1);
176 }
177 self.forward(to_ptr);
179 Some((to_ptr.cast::<Self>(), true))
181 }
182 Err(fwd) => Some((fwd.cast::<Self>(), false)),
183 }
184 }
185}
186
187impl<T: Trace> Trace for GcHeap<T> {
188 fn trace(&self, state: &mut GcState) {
189 if !self.is_marked() {
192 self.data.trace(state);
193 }
194 }
195}
196
197impl<T: PartialEq> PartialEq for GcHeap<T> {
198 fn eq(&self, other: &Self) -> bool {
199 self.data == other.data
200 }
201}
202
203impl<T: PartialEq> PartialEq<T> for GcHeap<T> {
204 fn eq(&self, other: &T) -> bool {
205 self.data == *other
206 }
207}
208
209impl<T: Eq> Eq for GcHeap<T> {}
210
211impl<T> Deref for GcHeap<T> {
212 type Target = T;
213
214 fn deref(&self) -> &Self::Target {
215 &self.data
216 }
217}
218
219impl<T> DerefMut for GcHeap<T> {
220 fn deref_mut(&mut self) -> &mut Self::Target {
221 &mut self.data
222 }
223}
224
225impl<T: fmt::Display> fmt::Display for GcHeap<T> {
226 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
227 write!(f, "{}", &self.data)
228 }
229}