use core::ptr;
use crate::Table;
use crate::function::UpVal;
use crate::gc::GcBarrier;
use crate::gc::{GCS_PAUSE, GCS_PROPAGATE_AGAIN};
use crate::gc::{GcObject, RawGcObject};
use crate::handle::RawHandle;
use crate::thread::Thread;
use crate::value::TValue;
impl GcBarrier for Thread {
unsafe fn barrier_value(&self, object: GcObject, value: TValue) {
if value.is_collectable() {
let child = value.gc_value();
unsafe {
if object.is_black() && child.is_white() {
self.barrier_forward(object, child);
}
}
}
}
unsafe fn object_barrier(&self, object: GcObject, child: GcObject) {
unsafe {
if object.is_black() && child.is_white() {
self.barrier_forward(object, child);
}
}
}
unsafe fn thread_barrier(&self) {
unsafe {
let object: GcObject = self.into();
if object.is_black() {
self.barrier_back(
object,
&raw mut self.as_ptr().as_mut().unwrap_unchecked().gc_list,
);
}
}
}
unsafe fn barrier_forward(&self, object: GcObject, value: GcObject) {
unsafe {
let global = self.global();
debug_assert!(object.is_black());
debug_assert!(value.is_white());
debug_assert!(!global.is_dead(value));
debug_assert!(!global.is_dead(object));
debug_assert_ne!(global.gc_state(), GCS_PAUSE);
if global.keep_invariant() {
global.really_mark_object(value);
} else {
global.make_white(object);
}
}
}
unsafe fn barrier_table(&self, table: Table, value: GcObject) {
unsafe {
let global = self.global();
let mut object: GcObject = table.into();
let gc_state = global.gc_state();
if !object.is_black() || !value.is_white() {
return;
}
if gc_state == GCS_PROPAGATE_AGAIN {
debug_assert!(!global.is_dead(value));
debug_assert!(!global.is_dead(object));
global.really_mark_object(value);
return;
}
debug_assert!(!global.is_dead(object));
debug_assert_ne!(gc_state, GCS_PAUSE);
object.black_to_gray();
table.set_gc_list(global.gray_again());
global.set_gray_again(Some(object));
}
}
unsafe fn barrier_back(&self, mut object: GcObject, gc_list: *mut *mut RawGcObject) {
unsafe {
let global = self.global();
debug_assert!(object.is_black());
debug_assert!(!global.is_dead(object));
debug_assert_ne!(global.gc_state(), GCS_PAUSE);
object.black_to_gray();
*gc_list = global
.gray_again()
.map_or(ptr::null_mut(), |object| object.as_ptr());
global.set_gray_again(Some(object));
}
}
unsafe fn upvalue_closed(&self, upvalue: UpVal) {
unsafe {
let global = self.global();
let mut object: GcObject = upvalue.into();
debug_assert!(!upvalue.is_open());
if object.is_gray() {
if global.keep_invariant() {
object.gray_to_black();
self.barrier_value(object, upvalue.closed_value());
} else {
global.make_white(object);
debug_assert_ne!(global.gc_state(), GCS_PAUSE);
}
}
}
}
}