From bbbe07a5dbe9fd747a62c202cfa5d4f2f3cbe52c Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Thu, 15 Aug 2024 13:22:39 -0400 Subject: [PATCH] Speed up finalizers for objects without object ID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the object being finalized does not have an object ID, then we don't need to insert into the object ID table, we can simply just allocate a new object ID by bumping the next_object_id counter. This speeds up finalization for objects that don't have an object ID. For example, the following script now runs faster: 1_000_000.times do o = Object.new ObjectSpace.define_finalizer(o) {} end Before: Time (mean ± σ): 1.462 s ± 0.019 s [User: 1.360 s, System: 0.094 s] Range (min … max): 1.441 s … 1.503 s 10 runs After: Time (mean ± σ): 1.199 s ± 0.015 s [User: 1.103 s, System: 0.086 s] Range (min … max): 1.181 s … 1.229 s 10 runs --- gc/default.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/gc/default.c b/gc/default.c index 28923a79c7..93f116a276 100644 --- a/gc/default.c +++ b/gc/default.c @@ -3045,6 +3045,19 @@ rb_gc_impl_copy_finalizer(void *objspace_ptr, VALUE dest, VALUE obj) } } +static VALUE +get_object_id_in_finalizer(rb_objspace_t *objspace, VALUE obj) +{ + if (FL_TEST(obj, FL_SEEN_OBJ_ID)) { + return rb_gc_impl_object_id(objspace, obj); + } + else { + VALUE id = ULL2NUM(objspace->next_object_id); + objspace->next_object_id += OBJ_ID_INCREMENT; + return id; + } +} + static VALUE get_final(long i, void *data) { @@ -3065,7 +3078,7 @@ run_final(rb_objspace_t *objspace, VALUE zombie) FL_UNSET(zombie, FL_FINALIZE); st_data_t table; if (st_delete(finalizer_table, &key, &table)) { - rb_gc_run_obj_finalizer(rb_gc_impl_object_id(objspace, zombie), RARRAY_LEN(table), get_final, (void *)table); + rb_gc_run_obj_finalizer(get_object_id_in_finalizer(objspace, zombie), RARRAY_LEN(table), get_final, (void *)table); } else { rb_bug("FL_FINALIZE flag is set, but finalizers are not found"); @@ -3248,7 +3261,7 @@ rb_gc_impl_shutdown_call_finalizer(void *objspace_ptr) while (list) { struct force_finalize_list *curr = list; - rb_gc_run_obj_finalizer(rb_gc_impl_object_id(objspace, curr->obj), RARRAY_LEN(curr->table), get_final, (void *)curr->table); + rb_gc_run_obj_finalizer(get_object_id_in_finalizer(objspace, curr->obj), RARRAY_LEN(curr->table), get_final, (void *)curr->table); st_data_t obj = (st_data_t)curr->obj; st_delete(finalizer_table, &obj, 0);