Skip to main content

luau_vm/gc/
barrier.rs

1use core::ptr;
2
3use crate::Table;
4use crate::function::UpVal;
5use crate::gc::GcBarrier;
6use crate::gc::{GCS_PAUSE, GCS_PROPAGATE_AGAIN};
7use crate::gc::{GcObject, RawGcObject};
8use crate::handle::RawHandle;
9use crate::thread::Thread;
10use crate::value::TValue;
11
12impl GcBarrier for Thread {
13    /// `luaC_barrier`
14    unsafe fn barrier_value(&self, object: GcObject, value: TValue) {
15        if value.is_collectable() {
16            let child = value.gc_value();
17            unsafe {
18                if object.is_black() && child.is_white() {
19                    self.barrier_forward(object, child);
20                }
21            }
22        }
23    }
24
25    /// `luaC_objbarrier`
26    unsafe fn object_barrier(&self, object: GcObject, child: GcObject) {
27        unsafe {
28            if object.is_black() && child.is_white() {
29                self.barrier_forward(object, child);
30            }
31        }
32    }
33
34    /// `luaC_threadbarrier`
35    unsafe fn thread_barrier(&self) {
36        unsafe {
37            let object: GcObject = self.into();
38            if object.is_black() {
39                self.barrier_back(
40                    object,
41                    &raw mut self.as_ptr().as_mut().unwrap_unchecked().gc_list,
42                );
43            }
44        }
45    }
46
47    /// `luaC_barrierf`
48    unsafe fn barrier_forward(&self, object: GcObject, value: GcObject) {
49        unsafe {
50            let global = self.global();
51
52            debug_assert!(object.is_black());
53            debug_assert!(value.is_white());
54            debug_assert!(!global.is_dead(value));
55            debug_assert!(!global.is_dead(object));
56            debug_assert_ne!(global.gc_state(), GCS_PAUSE);
57
58            if global.keep_invariant() {
59                global.really_mark_object(value);
60            } else {
61                global.make_white(object);
62            }
63        }
64    }
65
66    /// `luaC_barriertable`
67    unsafe fn barrier_table(&self, table: Table, value: GcObject) {
68        unsafe {
69            let global = self.global();
70            let mut object: GcObject = table.into();
71            let gc_state = global.gc_state();
72
73            if !object.is_black() || !value.is_white() {
74                return;
75            }
76
77            if gc_state == GCS_PROPAGATE_AGAIN {
78                debug_assert!(!global.is_dead(value));
79                debug_assert!(!global.is_dead(object));
80
81                global.really_mark_object(value);
82                return;
83            }
84
85            debug_assert!(!global.is_dead(object));
86            debug_assert_ne!(gc_state, GCS_PAUSE);
87
88            object.black_to_gray();
89            table.set_gc_list(global.gray_again());
90            global.set_gray_again(Some(object));
91        }
92    }
93
94    /// `luaC_barrierback`
95    unsafe fn barrier_back(&self, mut object: GcObject, gc_list: *mut *mut RawGcObject) {
96        unsafe {
97            let global = self.global();
98
99            debug_assert!(object.is_black());
100            debug_assert!(!global.is_dead(object));
101            debug_assert_ne!(global.gc_state(), GCS_PAUSE);
102
103            object.black_to_gray();
104            *gc_list = global
105                .gray_again()
106                .map_or(ptr::null_mut(), |object| object.as_ptr());
107            global.set_gray_again(Some(object));
108        }
109    }
110
111    /// `luaC_upvalclosed`
112    unsafe fn upvalue_closed(&self, upvalue: UpVal) {
113        unsafe {
114            let global = self.global();
115            let mut object: GcObject = upvalue.into();
116
117            debug_assert!(!upvalue.is_open());
118
119            if object.is_gray() {
120                if global.keep_invariant() {
121                    object.gray_to_black();
122                    self.barrier_value(object, upvalue.closed_value());
123                } else {
124                    global.make_white(object);
125                    debug_assert_ne!(global.gc_state(), GCS_PAUSE);
126                }
127            }
128        }
129    }
130}