1use std::{
5 marker::PhantomData,
6 ops::{Deref, DerefMut},
7 ptr::NonNull,
8};
9
10use crate::{GcHeap, GcPartitionId, GcTrace, GcWeak, weak::GcWeakRawId};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13#[repr(u8)]
14pub enum GcTriColor {
15 White = 0b00,
16 Gray = 0b01,
17 Black = 0b10,
18}
19
20impl From<GcTriColor> for u32 {
21 fn from(color: GcTriColor) -> Self {
22 color as u32
23 }
24}
25
26impl TryFrom<u32> for GcTriColor {
27 type Error = &'static str;
28
29 fn try_from(value: u32) -> Result<Self, Self::Error> {
30 match value {
31 0b00 => Ok(GcTriColor::White),
32 0b01 => Ok(GcTriColor::Gray),
33 0b10 => Ok(GcTriColor::Black),
34 _ => Err("Invalid value for TriColor"),
35 }
36 }
37}
38
39const COLOR_MASK: u32 = 0b11;
40
41bitflags::bitflags! {
42 #[repr(transparent)]
43 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
44 pub struct GcNodeFlag :u8 {
45 const ROOT = 1 << 5;
47
48 const LOCAL = 1 << 6;
50
51 const TRAVERSE_VISITED = 1 << 7;
53 }
54}
55
56pub struct GcHead {
58 pub(super) attrs: u32,
66
67 pub(super) partition: u32,
69
70 pub(super) weak_id: GcWeakRawId,
71
72 pub(super) next: Option<NonNull<GcHead>>,
74
75 #[cfg(debug_assertions)]
76 pub(crate) dbg_scope_depth: u8,
77 #[cfg(debug_assertions)]
78 pub(crate) dbg_string: std::borrow::Cow<'static, str>,
79}
80
81impl std::fmt::Debug for GcHead {
82 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 let mut s = f.debug_struct("GcNode");
84 s.field("ptr", &(self as *const Self))
85 .field("partition", &self.partition_id())
86 .field("color", &self.color())
87 .field("local", &self.is_local());
88
89 if self.is_root() {
90 s.field("root", &true);
91 }
92 if !self.weak_id.is_null() {
93 let w = self.weak_id;
94 s.field("weakref", &format!("{}#{}", w.index(), w.version()));
95 }
96
97 #[cfg(debug_assertions)]
98 {
99 s.field("scope", &self.dbg_scope_depth)
100 .field("dbg_string", &self.dbg_string);
101 }
102
103 s.finish()
104 }
105}
106
107impl GcHead {
108 #[inline(always)]
110 pub(crate) fn dtype(&self) -> u8 {
111 ((self.attrs & 0xFF00) >> 8) as u8
112 }
113
114 #[inline(always)]
116 pub(crate) fn color(&self) -> GcTriColor {
117 GcTriColor::try_from(self.attrs & COLOR_MASK).unwrap()
119 }
120
121 #[inline(always)]
123 pub(crate) fn set_color(&mut self, color: GcTriColor) {
124 self.attrs = (self.attrs & !COLOR_MASK) | (color as u32);
125 }
126
127 #[inline(always)]
128 pub(crate) fn flags(&self) -> GcNodeFlag {
129 GcNodeFlag::from_bits_truncate(self.attrs as u8)
130 }
131
132 #[inline(always)]
134 pub(crate) fn insert_flag(&mut self, flag: GcNodeFlag) {
135 self.attrs |= flag.bits() as u32;
136 }
137
138 #[inline(always)]
140 pub(crate) fn remove_flag(&mut self, flag: GcNodeFlag) {
141 self.attrs &= !(flag.bits() as u32);
142 }
143
144 #[inline(always)]
146 pub(crate) fn contains_flag(&self, flag: GcNodeFlag) -> bool {
147 (self.attrs & flag.bits() as u32) == flag.bits() as u32
148 }
149
150 #[inline(always)]
152 pub fn is_root(&self) -> bool {
153 self.contains_flag(GcNodeFlag::ROOT)
154 }
155
156 #[inline(always)]
157 pub fn is_local(&self) -> bool {
158 self.contains_flag(GcNodeFlag::LOCAL)
159 }
160
161 #[inline]
162 pub fn is_root_or_local(&self) -> bool {
163 let f = self.flags();
164 f.intersects(GcNodeFlag::ROOT | GcNodeFlag::LOCAL)
165 }
166
167 #[inline(always)]
168 pub(super) fn traverse_visited(&self) -> bool {
169 self.contains_flag(GcNodeFlag::TRAVERSE_VISITED)
170 }
171
172 #[inline(always)]
173 pub(super) fn set_traverse_visited(&mut self, visited: bool) {
174 if visited {
175 self.insert_flag(GcNodeFlag::TRAVERSE_VISITED);
176 } else {
177 self.remove_flag(GcNodeFlag::TRAVERSE_VISITED);
178 }
179 }
180
181 #[inline(always)]
183 pub fn partition_id(&self) -> GcPartitionId {
184 GcPartitionId((self.partition & 0x0000_FFFF) as u16)
185 }
186
187 #[inline(always)]
188 pub(crate) fn set_partition_id(&mut self, id: GcPartitionId) {
189 debug_assert!(self.partition_id().is_null() || self.partition_id() == id);
190 self.partition = (self.partition & 0xFFFF_0000) | id.0 as u32;
191 }
192
193 #[inline(always)]
195 pub fn payload(&self) -> NonNull<u8> {
196 #[cfg(debug_assertions)]
197 self.debug_assert_node_valid_simple();
198
199 unsafe { NonNull::from_ref(self).add(1).cast::<u8>() }
200 }
201}
202
203pub trait GcNode: GcTrace {
204 const GC_TYPE_ID: u8;
206
207 fn gc_ref(&self) -> GcRef<Self>
209 where
210 Self: std::marker::Sized;
211
212 #[inline(always)]
214 fn gc_head_ptr(&self) -> std::ptr::NonNull<GcHead>
215 where
216 Self: std::marker::Sized,
217 {
218 self.gc_ref().node_ptr()
219 }
220
221 #[inline(always)]
223 fn gc_head(&self) -> &GcHead
224 where
225 Self: std::marker::Sized,
226 {
227 unsafe { self.gc_head_ptr().as_ref() }
228 }
229
230 #[inline(always)]
232 fn gc_head_mut(&mut self) -> &mut GcHead
233 where
234 Self: std::marker::Sized,
235 {
236 unsafe { self.gc_head_ptr().as_mut() }
237 }
238}
239
240#[repr(transparent)]
242pub struct GcRef<T: GcNode> {
243 pub(super) head_ptr: NonNull<GcHead>,
244 pub(super) _marker: PhantomData<T>,
245}
246
247impl<T: GcNode> Deref for GcRef<T> {
248 type Target = T;
249
250 #[inline(always)]
251 fn deref(&self) -> &Self::Target {
252 unsafe { self.head_ptr.as_ref().payload().cast::<T>().as_ref() }
253 }
254}
255
256impl<T: GcNode> DerefMut for GcRef<T> {
257 #[inline(always)]
259 fn deref_mut(&mut self) -> &mut Self::Target {
260 unsafe { self.head_ptr.as_mut().payload().cast::<T>().as_mut() }
261 }
262}
263
264impl<T: GcNode> Clone for GcRef<T> {
265 fn clone(&self) -> Self {
266 *self
267 }
268}
269
270impl<T: GcNode> Copy for GcRef<T> {}
271
272impl<T: GcNode> PartialEq for GcRef<T> {
273 #[inline(always)]
274 fn eq(&self, other: &Self) -> bool {
275 self.head_ptr == other.head_ptr
276 }
277}
278
279impl<T: GcNode> Eq for GcRef<T> {}
280
281impl<T: GcNode> From<GcRef<T>> for NonNull<GcHead> {
282 #[inline(always)]
283 fn from(r: GcRef<T>) -> Self {
284 r.head_ptr
285 }
286}
287
288impl<T: GcNode> From<&GcRef<T>> for NonNull<GcHead> {
289 #[inline(always)]
290 fn from(r: &GcRef<T>) -> Self {
291 r.head_ptr
292 }
293}
294
295impl<T: GcNode> std::fmt::Debug for GcRef<T> {
296 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
297 unsafe { write!(f, "GcRef<{:?}>", self.head_ptr.as_ref()) }
298 }
299}
300
301impl<T: GcNode> GcRef<T> {
302 pub fn try_from_ref(heap: &GcHeap, data_ref: &T) -> Option<Self> {
317 let node = unsafe {
318 NonNull::from_ref(data_ref)
319 .cast::<u8>()
320 .sub(std::mem::size_of::<GcHead>())
321 .cast::<GcHead>()
322 };
323
324 if T::GC_TYPE_ID == unsafe { node.as_ref().dtype() } {
325 #[cfg(debug_assertions)]
326 unsafe {
327 node.as_ref().debug_assert_node_valid(heap);
328 }
329
330 Some(Self {
331 head_ptr: node,
332 _marker: PhantomData,
333 })
334 } else {
335 None
336 }
337 }
338
339 #[inline]
345 pub unsafe fn from_ref_unchecked(data_ref: &T) -> Self {
346 let node = unsafe { NonNull::from_ref(data_ref).cast::<GcHead>().sub(1) };
347
348 #[cfg(debug_assertions)]
349 unsafe {
350 node.as_ref().debug_assert_node_valid_simple();
351 }
352
353 Self {
354 head_ptr: node,
355 _marker: PhantomData,
356 }
357 }
358
359 pub fn with_mut<F, R>(&mut self, heap: &mut GcHeap, mutator: F) -> R
360 where
361 F: FnOnce(&mut T) -> R,
362 {
363 let head = unsafe { self.head_ptr.as_mut() };
364 if head.color() == GcTriColor::Black {
365 head.set_color(GcTriColor::Gray);
366 heap.add_gray_node(self.head_ptr);
367 }
368
369 let value = unsafe { head.payload().cast::<T>().as_mut() };
370 mutator(value)
371 }
372
373 #[inline]
374 pub fn as_ptr(&self) -> NonNull<T> {
375 unsafe { self.head_ptr.as_ref().payload().cast::<T>() }
376 }
377
378 #[inline(always)]
379 pub fn downgrade(&self, heap: &mut GcHeap) -> GcWeak<T> {
380 heap.downgrade(self)
381 }
382
383 #[inline(always)]
385 pub fn is_root(&self) -> bool {
386 unsafe { self.head_ptr.as_ref().is_root() }
387 }
388
389 #[inline(always)]
391 pub fn node_ptr(&self) -> NonNull<GcHead> {
392 self.head_ptr
393 }
394
395 #[inline(always)]
397 pub fn node_info(&self) -> &GcHead {
398 unsafe { self.head_ptr.as_ref() }
399 }
400}
401
402impl GcHeap {
403 #[deprecated(note = "no use")]
406 pub fn bind(&mut self, master: NonNull<GcHead>, mut slave: NonNull<GcHead>) {
407 #[cfg(debug_assertions)]
408 unsafe {
409 master.as_ref().debug_assert_node_valid(self);
410 slave.as_ref().debug_assert_node_valid(self);
411 }
412
413 unsafe {
415 if matches!(
416 (master.as_ref().color(), slave.as_ref().color()),
417 (GcTriColor::Black, GcTriColor::White | GcTriColor::Gray)
418 ) {
419 slave.as_mut().set_color(GcTriColor::Gray);
420
421 if self
422 .partition(slave.as_ref().partition_id())
423 .unwrap()
424 .is_marking()
425 {
426 self.add_gray_node(slave);
427 }
428 }
429 }
430
431 if unsafe { master.as_ref().partition_id() != slave.as_ref().partition_id() } {
432 let xref = unsafe {
434 let x = master.as_ref().xref();
435 if x.is_null() {
436 master.as_ref().partition_id()
437 } else {
438 x
439 }
440 };
441 self.set_xref(xref, slave);
442 }
443 }
444}
445
446#[cfg(debug_assertions)]
447impl GcHead {
448 pub fn debug_set_dbg_string(&mut self, str: std::borrow::Cow<'static, str>) {
449 self.dbg_string = str;
450 }
451
452 pub fn debug_dbg_string(&self) -> &std::borrow::Cow<'static, str> {
453 &self.dbg_string
454 }
455
456 pub fn debug_assert_node_valid_simple(&self) {
457 if !std::thread::panicking() {
458 debug_assert!(
459 ((self.attrs >> 24) & 0xFF) == 0xFF && self.next.is_none_or(|n| n.is_aligned()),
460 "bad node: {self:p}"
461 );
462 }
463 }
464
465 pub fn debug_assert_node_valid(&self, heap: &GcHeap) {
466 if !std::thread::panicking() {
467 debug_assert!(
468 heap.dbg_living_nodes.contains(&NonNull::from_ref(self)),
469 "[O.o] bad node: {self:p}"
470 );
471 self.debug_assert_node_valid_simple();
472 }
473 }
474}