11use crate :: {
2- GcObjectKind , LuaFunction , LuaTable , LuaValue ,
2+ Chunk , GcObjectKind , LuaFunction , LuaTable , LuaValue ,
33 lua_value:: { CClosureFunction , LuaString , LuaUpvalue , LuaUserdata , RClosureFunction } ,
44 lua_vm:: LuaState ,
55} ;
@@ -20,6 +20,7 @@ pub const WHITE0BIT: u8 = 3; // Object is white (type 0)
2020pub const WHITE1BIT : u8 = 4 ; // Object is white (type 1)
2121pub const BLACKBIT : u8 = 5 ; // Object is black
2222pub const FINALIZEDBIT : u8 = 6 ; // Object has been marked for finalization
23+ pub const SHAREDBIT : u8 = 7 ; // Object is shared across VMs and never collected
2324
2425// Bit masks
2526pub const WHITEBITS : u8 = ( 1 << WHITE0BIT ) | ( 1 << WHITE1BIT ) ;
@@ -180,6 +181,11 @@ impl GcHeader {
180181 ( self . marked ( ) & ( 1 << FINALIZEDBIT ) ) != 0
181182 }
182183
184+ #[ inline( always) ]
185+ pub fn is_shared ( & self ) -> bool {
186+ ( self . marked ( ) & ( 1 << SHAREDBIT ) ) != 0
187+ }
188+
183189 #[ inline( always) ]
184190 pub fn set_finalized ( & mut self ) {
185191 self . set_marked_bits ( self . marked ( ) | ( 1 << FINALIZEDBIT ) ) ;
@@ -190,6 +196,11 @@ impl GcHeader {
190196 self . set_marked_bits ( self . marked ( ) & !( 1 << FINALIZEDBIT ) ) ;
191197 }
192198
199+ #[ inline( always) ]
200+ pub fn make_shared ( & mut self ) {
201+ self . set_marked_bits ( self . marked ( ) | ( 1 << SHAREDBIT ) ) ;
202+ }
203+
193204 // ============ Color Transitions ============
194205
195206 #[ inline( always) ]
@@ -227,6 +238,9 @@ impl GcHeader {
227238 other_white == 0 || other_white == 1 ,
228239 "other_white must be 0 or 1"
229240 ) ;
241+ if self . is_shared ( ) {
242+ return false ;
243+ }
230244 ( self . marked ( ) & ( 1 << ( WHITE0BIT + other_white) ) ) != 0
231245 }
232246
@@ -290,6 +304,15 @@ pub struct Gc<T> {
290304 pub data : T ,
291305}
292306
307+ impl < T : std:: fmt:: Debug > std:: fmt:: Debug for Gc < T > {
308+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
309+ f. debug_struct ( "Gc" )
310+ . field ( "header" , & self . header )
311+ . field ( "data" , & self . data )
312+ . finish ( )
313+ }
314+ }
315+
293316impl < T > Gc < T > {
294317 pub fn new ( data : T , current_white : u8 , size : u32 ) -> Self {
295318 let mut header = GcHeader :: with_white ( current_white) ;
@@ -312,6 +335,7 @@ pub type GcRClosure = Gc<RClosureFunction>;
312335pub type GcUpvalue = Gc < LuaUpvalue > ;
313336pub type GcThread = Gc < LuaState > ;
314337pub type GcUserdata = Gc < LuaUserdata > ;
338+ pub type GcProto = Gc < Chunk > ;
315339
316340#[ derive( Debug ) ]
317341pub struct GcPtr < T : HasGcHeader > {
@@ -407,6 +431,7 @@ pub type CClosurePtr = GcPtr<GcCClosure>;
407431pub type RClosurePtr = GcPtr < GcRClosure > ;
408432pub type UserdataPtr = GcPtr < GcUserdata > ;
409433pub type ThreadPtr = GcPtr < GcThread > ;
434+ pub type ProtoPtr = GcPtr < GcProto > ;
410435
411436/// Compressed GcObjectPtr — tagged pointer in a single `u64` (8 bytes, was 16).
412437///
@@ -452,6 +477,7 @@ impl GcObjectPtr {
452477 const TAG_UPVALUE : u64 = 5 ;
453478 const TAG_THREAD : u64 = 6 ;
454479 const TAG_USERDATA : u64 = 7 ;
480+ const TAG_PROTO : u64 = 8 ;
455481 #[ inline( always) ]
456482 fn new_tagged ( ptr : u64 , tag : u64 ) -> Self {
457483 debug_assert ! (
@@ -565,6 +591,12 @@ impl GcObjectPtr {
565591 UserdataPtr :: from_raw ( self . raw_ptr ( ) )
566592 }
567593
594+ #[ inline( always) ]
595+ pub fn as_proto_ptr ( & self ) -> ProtoPtr {
596+ debug_assert ! ( self . tag( ) == Self :: TAG_PROTO as u8 ) ;
597+ ProtoPtr :: from_raw ( self . raw_ptr ( ) )
598+ }
599+
568600 // ============ Pattern matching helpers (for code that still uses if-let) ============
569601
570602 #[ inline( always) ]
@@ -606,6 +638,11 @@ impl GcObjectPtr {
606638 pub fn is_userdata ( & self ) -> bool {
607639 self . tag ( ) == Self :: TAG_USERDATA as u8
608640 }
641+
642+ #[ inline( always) ]
643+ pub fn is_proto ( & self ) -> bool {
644+ self . tag ( ) == Self :: TAG_PROTO as u8
645+ }
609646}
610647
611648impl From < StringPtr > for GcObjectPtr {
@@ -664,6 +701,13 @@ impl From<RClosurePtr> for GcObjectPtr {
664701 }
665702}
666703
704+ impl From < ProtoPtr > for GcObjectPtr {
705+ #[ inline( always) ]
706+ fn from ( ptr : ProtoPtr ) -> Self {
707+ Self :: new_tagged ( ptr. as_u64 ( ) , Self :: TAG_PROTO )
708+ }
709+ }
710+
667711// ============ GC-managed Objects ============
668712pub enum GcObjectOwner {
669713 String ( Box < GcString > ) ,
@@ -674,6 +718,7 @@ pub enum GcObjectOwner {
674718 Userdata ( Box < GcUserdata > ) ,
675719 CClosure ( Box < GcCClosure > ) ,
676720 RClosure ( Box < GcRClosure > ) ,
721+ Proto ( Box < GcProto > ) ,
677722}
678723
679724impl GcObjectOwner {
@@ -694,7 +739,7 @@ impl GcObjectOwner {
694739 base + array_bytes + hash_bytes
695740 }
696741 GcObjectOwner :: Function ( f) => {
697- f . data . chunk ( ) . proto_data_size as usize + std:: mem:: size_of_val ( f. data . upvalues ( ) )
742+ std :: mem :: size_of :: < GcFunction > ( ) + std:: mem:: size_of_val ( f. data . upvalues ( ) )
698743 }
699744 GcObjectOwner :: CClosure ( c) => {
700745 std:: mem:: size_of :: < GcCClosure > ( )
@@ -707,6 +752,9 @@ impl GcObjectOwner {
707752 GcObjectOwner :: Upvalue ( _) => 64 , // fixed estimate
708753 GcObjectOwner :: Thread ( t) => std:: mem:: size_of :: < GcThread > ( ) + t. data . stack . len ( ) * 16 ,
709754 GcObjectOwner :: Userdata ( _) => std:: mem:: size_of :: < GcUserdata > ( ) ,
755+ GcObjectOwner :: Proto ( p) => {
756+ std:: mem:: size_of :: < GcProto > ( ) + p. data . proto_data_size as usize
757+ }
710758 }
711759 }
712760
@@ -726,6 +774,7 @@ impl GcObjectOwner {
726774 GcObjectOwner :: Upvalue ( u) => & u. header ,
727775 GcObjectOwner :: Thread ( t) => & t. header ,
728776 GcObjectOwner :: Userdata ( u) => & u. header ,
777+ GcObjectOwner :: Proto ( p) => & p. header ,
729778 } ) as _
730779 }
731780
@@ -739,6 +788,7 @@ impl GcObjectOwner {
739788 GcObjectOwner :: Upvalue ( u) => & mut u. header ,
740789 GcObjectOwner :: Thread ( t) => & mut t. header ,
741790 GcObjectOwner :: Userdata ( u) => & mut u. header ,
791+ GcObjectOwner :: Proto ( p) => & mut p. header ,
742792 } ) as _
743793 }
744794
@@ -800,6 +850,13 @@ impl GcObjectOwner {
800850 }
801851 }
802852
853+ pub fn as_proto_ptr ( & self ) -> Option < ProtoPtr > {
854+ match self {
855+ GcObjectOwner :: Proto ( p) => Some ( ProtoPtr :: new ( p. as_ref ( ) as * const GcProto ) ) ,
856+ _ => None ,
857+ }
858+ }
859+
803860 pub fn as_gc_ptr ( & self ) -> GcObjectPtr {
804861 match self {
805862 GcObjectOwner :: String ( s) => {
@@ -826,6 +883,9 @@ impl GcObjectOwner {
826883 GcObjectOwner :: RClosure ( r) => {
827884 GcObjectPtr :: from ( RClosurePtr :: new ( r. as_ref ( ) as * const GcRClosure ) )
828885 }
886+ GcObjectOwner :: Proto ( p) => {
887+ GcObjectPtr :: from ( ProtoPtr :: new ( p. as_ref ( ) as * const GcProto ) )
888+ }
829889 }
830890 }
831891
@@ -878,6 +938,13 @@ impl GcObjectOwner {
878938 }
879939 }
880940
941+ pub fn as_proto_mut ( & mut self ) -> Option < & mut Chunk > {
942+ match self {
943+ GcObjectOwner :: Proto ( p) => Some ( & mut p. data ) ,
944+ _ => None ,
945+ }
946+ }
947+
881948 pub fn size_of_data ( & self ) -> usize {
882949 self . header ( ) . size as usize
883950 }
0 commit comments