diff --git a/gc.c b/gc.c index 67ec968bd9..ab75d6752a 100644 --- a/gc.c +++ b/gc.c @@ -8491,6 +8491,7 @@ gc_update_references(rb_objspace_t * objspace) objspace_each_objects_without_setup(objspace, gc_ref_update, objspace); rb_vm_update_references(vm); rb_transient_heap_update_references(); + rb_gc_update_global_tbl(); global_symbols.ids = rb_gc_location(global_symbols.ids); global_symbols.dsymbol_fstr_hash = rb_gc_location(global_symbols.dsymbol_fstr_hash); gc_update_tbl_refs(objspace, objspace->obj_to_id_tbl); diff --git a/internal/variable.h b/internal/variable.h index a3b8f7963d..8defc1523c 100644 --- a/internal/variable.h +++ b/internal/variable.h @@ -28,6 +28,7 @@ struct rb_global_entry { /* variable.c */ void rb_gc_mark_global_tbl(void); +void rb_gc_update_global_tbl(void); size_t rb_generic_ivar_memsize(VALUE); VALUE rb_search_class_path(VALUE); VALUE rb_attr_delete(VALUE, ID); diff --git a/variable.c b/variable.c index 3bcee434da..dad20f2f7b 100644 --- a/variable.c +++ b/variable.c @@ -36,6 +36,8 @@ #include "variable.h" #include "vm_core.h" +typedef void rb_gvar_compact_t(void *var); + static struct rb_id_table *rb_global_tbl; static ID autoload, classpath, tmp_classpath; static VALUE autoload_featuremap; /* feature => autoload_i */ @@ -316,6 +318,7 @@ struct rb_global_variable { rb_gvar_getter_t *getter; rb_gvar_setter_t *setter; rb_gvar_marker_t *marker; + rb_gvar_compact_t *compactor; struct trace_var *trace; }; @@ -333,6 +336,11 @@ rb_find_global_entry(ID id) return entry; } +static void +rb_gvar_undef_compactor(void *var) +{ +} + MJIT_FUNC_EXPORTED struct rb_global_entry* rb_global_entry(ID id) { @@ -348,6 +356,7 @@ rb_global_entry(ID id) var->getter = rb_gvar_undef_getter; var->setter = rb_gvar_undef_setter; var->marker = rb_gvar_undef_marker; + var->compactor = rb_gvar_undef_compactor; var->block_trace = 0; var->trace = 0; @@ -364,6 +373,21 @@ rb_gvar_undef_getter(ID id, VALUE *_) return Qnil; } +static void +rb_gvar_val_compactor(void *_var) +{ + struct rb_global_variable *var = (struct rb_global_variable *)_var; + + VALUE obj = (VALUE)var->data; + + if (obj) { + VALUE new = rb_gc_location(obj); + if (new != obj) { + var->data = (void*)new; + } + } +} + void rb_gvar_undef_setter(VALUE val, ID id, VALUE *_) { @@ -371,6 +395,7 @@ rb_gvar_undef_setter(VALUE val, ID id, VALUE *_) var->getter = rb_gvar_val_getter; var->setter = rb_gvar_val_setter; var->marker = rb_gvar_val_marker; + var->compactor = rb_gvar_val_compactor; var->data = (void*)val; } @@ -397,7 +422,7 @@ void rb_gvar_val_marker(VALUE *var) { VALUE data = (VALUE)var; - if (data) rb_gc_mark(data); + if (data) rb_gc_mark_movable(data); } VALUE @@ -448,6 +473,23 @@ rb_gc_mark_global_tbl(void) rb_id_table_foreach_values(rb_global_tbl, mark_global_entry, 0); } +static enum rb_id_table_iterator_result +update_global_entry(VALUE v, void *ignored) +{ + struct rb_global_entry *entry = (struct rb_global_entry *)v; + struct rb_global_variable *var = entry->var; + + (*var->compactor)(var); + return ID_TABLE_CONTINUE; +} + +void +rb_gc_update_global_tbl(void) +{ + if (rb_global_tbl) + rb_id_table_foreach_values(rb_global_tbl, update_global_entry, 0); +} + static ID global_id(const char *name) {