@@ -12,6 +12,8 @@ struct objspace {
1212 st_table * id_to_obj_tbl ;
1313 st_table * obj_to_id_tbl ;
1414 unsigned long long next_object_id ;
15+
16+ st_table * finalizer_table ;
1517};
1618
1719bool
@@ -85,6 +87,8 @@ rb_gc_impl_objspace_init(void *objspace_ptr)
8587 struct objspace * objspace = objspace_ptr ;
8688
8789 objspace_obj_id_init (objspace );
90+
91+ objspace -> finalizer_table = st_init_numtable ();
8892}
8993
9094void
@@ -195,7 +199,6 @@ rb_gc_impl_config_set(void *objspace_ptr, VALUE hash)
195199VALUE
196200rb_gc_impl_new_obj (void * objspace_ptr , void * cache_ptr , VALUE klass , VALUE flags , VALUE v1 , VALUE v2 , VALUE v3 , bool wb_protected , size_t alloc_size )
197201{
198- #define MMTK_MIN_OBJ_ALIGN 8
199202#define MMTK_ALLOCATION_SEMANTICS_DEFAULT 0
200203 if (alloc_size > 640 ) rb_bug ("too big" );
201204 for (int i = 0 ; i < 5 ; i ++ ) {
@@ -206,7 +209,7 @@ rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags
206209 }
207210 }
208211
209- VALUE * alloc_obj = mmtk_alloc (cache_ptr , alloc_size + 8 , MMTK_MIN_OBJ_ALIGN , 0 , MMTK_ALLOCATION_SEMANTICS_DEFAULT );
212+ VALUE * alloc_obj = mmtk_alloc (cache_ptr , alloc_size + 8 , MMTk_MIN_OBJ_ALIGN , 0 , MMTK_ALLOCATION_SEMANTICS_DEFAULT );
210213 alloc_obj ++ ;
211214 alloc_obj [-1 ] = alloc_size ;
212215 alloc_obj [0 ] = flags ;
@@ -344,13 +347,119 @@ rb_gc_impl_make_zombie(void *objspace_ptr, VALUE obj, void (*dfree)(void *), voi
344347 dfree (data );
345348}
346349
347- VALUE rb_gc_impl_define_finalizer (void * objspace_ptr , VALUE obj , VALUE block ) { }
348- VALUE rb_gc_impl_undefine_finalizer (void * objspace_ptr , VALUE obj ) { }
349- void rb_gc_impl_copy_finalizer (void * objspace_ptr , VALUE dest , VALUE obj ) { }
350+ VALUE
351+ rb_gc_impl_define_finalizer (void * objspace_ptr , VALUE obj , VALUE block )
352+ {
353+ struct objspace * objspace = objspace_ptr ;
354+ VALUE table ;
355+ st_data_t data ;
356+
357+ RBASIC (obj )-> flags |= FL_FINALIZE ;
358+
359+ if (st_lookup (objspace -> finalizer_table , obj , & data )) {
360+ table = (VALUE )data ;
361+
362+ /* avoid duplicate block, table is usually small */
363+ {
364+ long len = RARRAY_LEN (table );
365+ long i ;
366+
367+ for (i = 0 ; i < len ; i ++ ) {
368+ VALUE recv = RARRAY_AREF (table , i );
369+ if (rb_equal (recv , block )) {
370+ return recv ;
371+ }
372+ }
373+ }
374+
375+ rb_ary_push (table , block );
376+ }
377+ else {
378+ table = rb_ary_new3 (1 , block );
379+ rb_obj_hide (table );
380+ st_add_direct (objspace -> finalizer_table , obj , table );
381+ }
382+
383+ return block ;
384+ }
385+
386+ void
387+ rb_gc_impl_undefine_finalizer (void * objspace_ptr , VALUE obj )
388+ {
389+ struct objspace * objspace = objspace_ptr ;
390+
391+ st_data_t data = obj ;
392+ st_delete (objspace -> finalizer_table , & data , 0 );
393+ FL_UNSET (obj , FL_FINALIZE );
394+ }
395+
396+ void
397+ rb_gc_impl_copy_finalizer (void * objspace_ptr , VALUE dest , VALUE obj )
398+ {
399+ struct objspace * objspace = objspace_ptr ;
400+ VALUE table ;
401+ st_data_t data ;
402+
403+ if (!FL_TEST (obj , FL_FINALIZE )) return ;
404+
405+ if (RB_LIKELY (st_lookup (objspace -> finalizer_table , obj , & data ))) {
406+ table = (VALUE )data ;
407+ st_insert (objspace -> finalizer_table , dest , table );
408+ FL_SET (dest , FL_FINALIZE );
409+ }
410+ else {
411+ rb_bug ("rb_gc_copy_finalizer: FL_FINALIZE set but not found in finalizer_table: %s" , rb_obj_info (obj ));
412+ }
413+ }
414+
415+ struct force_finalize_list {
416+ VALUE obj ;
417+ VALUE table ;
418+ struct force_finalize_list * next ;
419+ };
420+
421+ static int
422+ force_chain_object (st_data_t key , st_data_t val , st_data_t arg )
423+ {
424+ struct force_finalize_list * * prev = (struct force_finalize_list * * )arg ;
425+ struct force_finalize_list * curr = ALLOC (struct force_finalize_list );
426+ curr -> obj = key ;
427+ curr -> table = val ;
428+ curr -> next = * prev ;
429+ * prev = curr ;
430+ return ST_CONTINUE ;
431+ }
432+
433+ static VALUE
434+ get_final (long i , void * data )
435+ {
436+ VALUE table = (VALUE )data ;
437+
438+ return RARRAY_AREF (table , i );
439+ }
350440
351441void
352442rb_gc_impl_shutdown_call_finalizer (void * objspace_ptr )
353443{
444+ struct objspace * objspace = objspace_ptr ;
445+
446+ while (objspace -> finalizer_table -> num_entries ) {
447+ struct force_finalize_list * list = NULL ;
448+ st_foreach (objspace -> finalizer_table , force_chain_object , (st_data_t )& list );
449+ while (list ) {
450+ struct force_finalize_list * curr = list ;
451+
452+ st_data_t obj = (st_data_t )curr -> obj ;
453+ st_delete (objspace -> finalizer_table , & obj , 0 );
454+ FL_UNSET (curr -> obj , FL_FINALIZE );
455+
456+ rb_gc_run_obj_finalizer (rb_gc_impl_object_id (objspace , curr -> obj ), RARRAY_LEN (curr -> table ), get_final , (void * )curr -> table );
457+
458+ list = curr -> next ;
459+ xfree (curr );
460+ }
461+ }
462+
354463 struct MMTk_RawVecOfObjRef registered_candidates = mmtk_get_all_obj_free_candidates ();
355464 for (size_t i = 0 ; i < registered_candidates .len ; i ++ ) {
356465 VALUE obj = (VALUE )registered_candidates .ptr [i ];
0 commit comments