luau-vm 0.732.0

Pure-Rust Luau virtual machine, garbage collector, and standard libraries
Documentation
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 {
    /// `luaC_barrier`
    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);
                }
            }
        }
    }

    /// `luaC_objbarrier`
    unsafe fn object_barrier(&self, object: GcObject, child: GcObject) {
        unsafe {
            if object.is_black() && child.is_white() {
                self.barrier_forward(object, child);
            }
        }
    }

    /// `luaC_threadbarrier`
    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,
                );
            }
        }
    }

    /// `luaC_barrierf`
    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);
            }
        }
    }

    /// `luaC_barriertable`
    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));
        }
    }

    /// `luaC_barrierback`
    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));
        }
    }

    /// `luaC_upvalclosed`
    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);
                }
            }
        }
    }
}