Skip to content

Commit c4c47bf

Browse files
committed
Implement finalizers
1 parent b3a00bf commit c4c47bf

File tree

1 file changed

+114
-5
lines changed

1 file changed

+114
-5
lines changed

gc/mmtk.c

Lines changed: 114 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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

1719
bool
@@ -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

9094
void
@@ -195,7 +199,6 @@ rb_gc_impl_config_set(void *objspace_ptr, VALUE hash)
195199
VALUE
196200
rb_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

351441
void
352442
rb_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

Comments
 (0)