@@ -712,6 +712,7 @@ struct free_slot {
712712struct object_metadata {
713713 unsigned char age : RVALUE_AGE_BIT_COUNT ;
714714 unsigned char seen_obj_id : 1 ;
715+ unsigned char has_finalizer : 1 ;
715716};
716717STATIC_ASSERT (SIZEOF_OBJECT_METADATA , sizeof (struct object_metadata ) == 1 );
717718
@@ -2629,15 +2630,13 @@ rb_gc_impl_pointer_to_heap_p(void *objspace_ptr, const void *ptr)
26292630 return is_pointer_to_heap (objspace_ptr , ptr );
26302631}
26312632
2632- #define ZOMBIE_OBJ_KEPT_FLAGS (FL_FINALIZE)
2633-
26342633void
26352634rb_gc_impl_make_zombie (void * objspace_ptr , VALUE obj , void (* dfree )(void * ), void * data )
26362635{
26372636 rb_objspace_t * objspace = objspace_ptr ;
26382637
26392638 struct RZombie * zombie = RZOMBIE (obj );
2640- zombie -> basic .flags = T_ZOMBIE | ( zombie -> basic . flags & ZOMBIE_OBJ_KEPT_FLAGS ) ;
2639+ zombie -> basic .flags = T_ZOMBIE ;
26412640 zombie -> dfree = dfree ;
26422641 zombie -> data = data ;
26432642 VALUE prev , next = heap_pages_deferred_final ;
@@ -2827,7 +2826,7 @@ rb_gc_impl_define_finalizer(void *objspace_ptr, VALUE obj, VALUE block)
28272826
28282827 GC_ASSERT (!OBJ_FROZEN (obj ));
28292828
2830- RBASIC (obj )-> flags |= FL_FINALIZE ;
2829+ RVALUE_METADATA (obj )-> has_finalizer = 1 ;
28312830
28322831 if (st_lookup (finalizer_table , obj , & data )) {
28332832 table = (VALUE )data ;
@@ -2865,7 +2864,7 @@ rb_gc_impl_undefine_finalizer(void *objspace_ptr, VALUE obj)
28652864
28662865 st_data_t data = obj ;
28672866 st_delete (finalizer_table , & data , 0 );
2868- FL_UNSET (obj , FL_FINALIZE ) ;
2867+ RVALUE_METADATA (obj ) -> has_finalizer = 0 ;
28692868}
28702869
28712870void
@@ -2875,15 +2874,15 @@ rb_gc_impl_copy_finalizer(void *objspace_ptr, VALUE dest, VALUE obj)
28752874 VALUE table ;
28762875 st_data_t data ;
28772876
2878- if (!FL_TEST (obj , FL_FINALIZE ) ) return ;
2877+ if (!RVALUE_METADATA (obj ) -> has_finalizer ) return ;
28792878
28802879 if (RB_LIKELY (st_lookup (finalizer_table , obj , & data ))) {
28812880 table = (VALUE )data ;
28822881 st_insert (finalizer_table , dest , table );
2883- FL_SET (dest , FL_FINALIZE ) ;
2882+ RVALUE_METADATA (dest ) -> has_finalizer = 1 ;
28842883 }
28852884 else {
2886- rb_bug ("rb_gc_copy_finalizer: FL_FINALIZE set but not found in finalizer_table: %s" , rb_obj_info (obj ));
2885+ rb_bug ("rb_gc_copy_finalizer: has_finalizer set but not found in finalizer_table: %s" , rb_obj_info (obj ));
28872886 }
28882887}
28892888
@@ -2916,18 +2915,25 @@ run_final(rb_objspace_t *objspace, VALUE zombie)
29162915 }
29172916
29182917 st_data_t key = (st_data_t )zombie ;
2919- if (FL_TEST_RAW (zombie , FL_FINALIZE )) {
2920- FL_UNSET (zombie , FL_FINALIZE );
2918+ bool has_finalizer = RVALUE_METADATA (zombie )-> has_finalizer ;
2919+
2920+ if (has_finalizer ) {
2921+ RVALUE_METADATA (zombie )-> has_finalizer = 0 ;
2922+
29212923 st_data_t table ;
29222924 if (st_delete (finalizer_table , & key , & table )) {
29232925 rb_gc_run_obj_finalizer (get_object_id_in_finalizer (objspace , zombie ), RARRAY_LEN (table ), get_final , (void * )table );
29242926 }
29252927 else {
2926- rb_bug ("FL_FINALIZE flag is set, but finalizers are not found" );
2928+ rb_bug ("Finalizer metadata is set, but finalizers are not found" );
29272929 }
29282930 }
29292931 else {
2930- GC_ASSERT (!st_lookup (finalizer_table , key , NULL ));
2932+ if (st_lookup (finalizer_table , key , NULL )) {
2933+ st_data_t ignore ;
2934+ st_delete (finalizer_table , & key , & ignore );
2935+ rb_bug ("Finalizer table entry exists but metadata is not set" );
2936+ }
29312937 }
29322938}
29332939
@@ -3067,12 +3073,12 @@ rb_gc_impl_shutdown_call_finalizer_i(st_data_t key, st_data_t val, st_data_t dat
30673073 VALUE obj = (VALUE )key ;
30683074 VALUE table = (VALUE )val ;
30693075
3070- GC_ASSERT (RB_FL_TEST (obj , FL_FINALIZE ) );
3076+ GC_ASSERT (RVALUE_METADATA (obj ) -> has_finalizer );
30713077 GC_ASSERT (RB_BUILTIN_TYPE (val ) == T_ARRAY );
30723078
30733079 rb_gc_run_obj_finalizer (rb_gc_impl_object_id (objspace , obj ), RARRAY_LEN (table ), get_final , (void * )table );
30743080
3075- FL_UNSET (obj , FL_FINALIZE ) ;
3081+ RVALUE_METADATA (obj ) -> has_finalizer = 0 ;
30763082
30773083 return ST_DELETE ;
30783084}
@@ -5061,15 +5067,16 @@ verify_internal_consistency_i(void *page_start, void *page_end, size_t stride,
50615067 if (BUILTIN_TYPE (obj ) == T_ZOMBIE ) {
50625068 data -> zombie_object_count ++ ;
50635069
5064- if (( RBASIC (obj )-> flags & ~ ZOMBIE_OBJ_KEPT_FLAGS ) != T_ZOMBIE ) {
5070+ if (RBASIC (obj )-> flags != T_ZOMBIE ) {
50655071 fprintf (stderr , "verify_internal_consistency_i: T_ZOMBIE has extra flags set: %s\n" ,
50665072 rb_obj_info (obj ));
50675073 data -> err_count ++ ;
50685074 }
50695075
5070- if (!!FL_TEST (obj , FL_FINALIZE ) != !!st_is_member (finalizer_table , obj )) {
5071- fprintf (stderr , "verify_internal_consistency_i: FL_FINALIZE %s but %s finalizer_table: %s\n" ,
5072- FL_TEST (obj , FL_FINALIZE ) ? "set" : "not set" , st_is_member (finalizer_table , obj ) ? "in" : "not in" ,
5076+ if (!!RVALUE_METADATA (obj )-> has_finalizer != !!st_is_member (finalizer_table , obj )) {
5077+ fprintf (stderr , "verify_internal_consistency_i: Finalizer metadata %s but %s finalizer_table: %s\n" ,
5078+ RVALUE_METADATA (obj )-> has_finalizer ? "set" : "not set" ,
5079+ st_is_member (finalizer_table , obj ) ? "in" : "not in" ,
50735080 rb_obj_info (obj ));
50745081 data -> err_count ++ ;
50755082 }
@@ -6202,15 +6209,15 @@ rb_gc_impl_writebarrier_remember(void *objspace_ptr, VALUE obj)
62026209 }
62036210}
62046211
6205- #define RB_GC_OBJECT_METADATA_ENTRY_COUNT 7
6212+ #define RB_GC_OBJECT_METADATA_ENTRY_COUNT 8
62066213static struct rb_gc_object_metadata_entry object_metadata_entries [RB_GC_OBJECT_METADATA_ENTRY_COUNT + 1 ];
62076214
62086215struct rb_gc_object_metadata_entry *
62096216rb_gc_impl_object_metadata (void * objspace_ptr , VALUE obj )
62106217{
62116218 rb_objspace_t * objspace = objspace_ptr ;
62126219 size_t n = 0 ;
6213- static ID ID_wb_protected , ID_age , ID_old , ID_uncollectible , ID_marking , ID_marked , ID_pinned , ID_object_id ;
6220+ static ID ID_wb_protected , ID_age , ID_old , ID_uncollectible , ID_marking , ID_marked , ID_pinned , ID_object_id , ID_has_finalizer ;
62146221
62156222 if (!ID_marked ) {
62166223#define I (s ) ID_##s = rb_intern(#s);
@@ -6222,6 +6229,7 @@ rb_gc_impl_object_metadata(void *objspace_ptr, VALUE obj)
62226229 I (marked );
62236230 I (pinned );
62246231 I (object_id );
6232+ I (has_finalizer );
62256233#undef I
62266234 }
62276235
@@ -6240,6 +6248,7 @@ rb_gc_impl_object_metadata(void *objspace_ptr, VALUE obj)
62406248 if (RVALUE_MARKED (objspace , obj )) SET_ENTRY (marked , Qtrue );
62416249 if (RVALUE_PINNED (objspace , obj )) SET_ENTRY (pinned , Qtrue );
62426250 if (rb_gc_impl_object_id_seen_p (obj )) SET_ENTRY (object_id , rb_obj_id (obj ));
6251+ if (RVALUE_METADATA (obj )-> has_finalizer ) SET_ENTRY (has_finalizer , Qtrue );
62436252
62446253 object_metadata_entries [n ].name = 0 ;
62456254 object_metadata_entries [n ].val = 0 ;
@@ -6248,6 +6257,12 @@ rb_gc_impl_object_metadata(void *objspace_ptr, VALUE obj)
62486257 return object_metadata_entries ;
62496258}
62506259
6260+ bool
6261+ rb_gc_impl_has_finalizer (VALUE obj )
6262+ {
6263+ return RVALUE_METADATA (obj )-> has_finalizer ;
6264+ }
6265+
62516266void *
62526267rb_gc_impl_ractor_cache_alloc (void * objspace_ptr , void * ractor )
62536268{
@@ -6906,7 +6921,7 @@ gc_is_moveable_obj(rb_objspace_t *objspace, VALUE obj)
69066921 case T_RATIONAL :
69076922 case T_NODE :
69086923 case T_CLASS :
6909- if (FL_TEST_RAW (obj , FL_FINALIZE ) ) {
6924+ if (RVALUE_METADATA (obj ) -> has_finalizer ) {
69106925 /* The finalizer table is a numtable. It looks up objects by address.
69116926 * We can't mark the keys in the finalizer table because that would
69126927 * prevent the objects from being collected. This check prevents
0 commit comments