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 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 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 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 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 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 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 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}