Skip to content

Commit

Permalink
Use rb_gc_mark_and_move for imemo
Browse files Browse the repository at this point in the history
  • Loading branch information
peterzhu2118 committed Feb 20, 2024
1 parent 20f0310 commit c184aa8
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 216 deletions.
271 changes: 95 additions & 176 deletions gc.c
Expand Up @@ -4710,6 +4710,14 @@ is_live_object(rb_objspace_t *objspace, VALUE ptr)
}
}

static bool
moved_or_living_object_strictly_p(rb_objspace_t *objspace, VALUE obj)
{
return obj &&
is_pointer_to_heap(objspace, (void *)obj) &&
(is_live_object(objspace, obj) || BUILTIN_TYPE(obj) == T_MOVED);
}

static inline int
is_markable_object(VALUE obj)
{
Expand Down Expand Up @@ -6675,38 +6683,44 @@ rb_mark_hash(st_table *tbl)
}

static void
mark_method_entry(rb_objspace_t *objspace, const rb_method_entry_t *me)
mark_and_move_method_entry(rb_objspace_t *objspace, rb_method_entry_t *me, bool reference_updating)
{
const rb_method_definition_t *def = me->def;
rb_method_definition_t *def = me->def;

gc_mark(objspace, me->owner);
gc_mark(objspace, me->defined_class);
rb_gc_mark_and_move(&me->owner);
rb_gc_mark_and_move(&me->defined_class);

if (def) {
switch (def->type) {
case VM_METHOD_TYPE_ISEQ:
if (def->body.iseq.iseqptr) gc_mark(objspace, (VALUE)def->body.iseq.iseqptr);
gc_mark(objspace, (VALUE)def->body.iseq.cref);
if (def->body.iseq.iseqptr) {
rb_gc_mark_and_move_ptr(&def->body.iseq.iseqptr);
}
rb_gc_mark_and_move_ptr(&def->body.iseq.cref);

if (def->iseq_overload && me->defined_class) {
// it can be a key of "overloaded_cme" table
// so it should be pinned.
gc_mark_and_pin(objspace, (VALUE)me);
if (!reference_updating) {
if (def->iseq_overload && me->defined_class) {
// it can be a key of "overloaded_cme" table
// so it should be pinned.
gc_mark_and_pin(objspace, (VALUE)me);
}
}
break;
case VM_METHOD_TYPE_ATTRSET:
case VM_METHOD_TYPE_IVAR:
gc_mark(objspace, def->body.attr.location);
rb_gc_mark_and_move(&def->body.attr.location);
break;
case VM_METHOD_TYPE_BMETHOD:
gc_mark(objspace, def->body.bmethod.proc);
if (def->body.bmethod.hooks) rb_hook_list_mark(def->body.bmethod.hooks);
rb_gc_mark_and_move(&def->body.bmethod.proc);
if (!reference_updating) {
if (def->body.bmethod.hooks) rb_hook_list_mark(def->body.bmethod.hooks);
}
break;
case VM_METHOD_TYPE_ALIAS:
gc_mark(objspace, (VALUE)def->body.alias.original_me);
rb_gc_mark_and_move_ptr(&def->body.alias.original_me);
return;
case VM_METHOD_TYPE_REFINED:
gc_mark(objspace, (VALUE)def->body.refined.orig_me);
rb_gc_mark_and_move_ptr(&def->body.refined.orig_me);
break;
case VM_METHOD_TYPE_CFUNC:
case VM_METHOD_TYPE_ZSUPER:
Expand Down Expand Up @@ -7189,65 +7203,80 @@ gc_mark_set_parent(rb_objspace_t *objspace, VALUE obj)
}

static void
gc_mark_imemo(rb_objspace_t *objspace, VALUE obj)
gc_mark_and_move_imemo(rb_objspace_t *objspace, VALUE obj, bool reference_updating)
{
switch (imemo_type(obj)) {
case imemo_env:
{
const rb_env_t *env = (const rb_env_t *)obj;
rb_env_t *env = (rb_env_t *)obj;

if (LIKELY(env->ep)) {
// just after newobj() can be NULL here.
GC_ASSERT(env->ep[VM_ENV_DATA_INDEX_ENV] == obj);
GC_ASSERT(VM_ENV_ESCAPED_P(env->ep));
rb_gc_mark_values((long)env->env_size, env->env);
VM_ENV_FLAGS_SET(env->ep, VM_ENV_FLAG_WB_REQUIRED);
gc_mark(objspace, (VALUE)rb_vm_env_prev_env(env));
gc_mark(objspace, (VALUE)env->iseq);
GC_ASSERT(rb_gc_location(env->ep[VM_ENV_DATA_INDEX_ENV]) == rb_gc_location(obj));
GC_ASSERT(reference_updating || VM_ENV_ESCAPED_P(env->ep));

for (unsigned int i = 0; i < env->env_size; i++) {
rb_gc_mark_and_move((VALUE *)&env->env[i]);
}

rb_gc_mark_and_move_ptr(&env->iseq);

if (reference_updating) {
UPDATE_IF_MOVED(objspace, env->ep[VM_ENV_DATA_INDEX_ENV]);
}
else {
VM_ENV_FLAGS_SET(env->ep, VM_ENV_FLAG_WB_REQUIRED);
gc_mark(objspace, (VALUE)rb_vm_env_prev_env(env));
}
}
}
return;
case imemo_cref:
gc_mark(objspace, RANY(obj)->as.imemo.cref.klass_or_self);
gc_mark(objspace, (VALUE)RANY(obj)->as.imemo.cref.next);
gc_mark(objspace, RANY(obj)->as.imemo.cref.refinements);
rb_gc_mark_and_move(&RANY(obj)->as.imemo.cref.klass_or_self);
rb_gc_mark_and_move_ptr(&RANY(obj)->as.imemo.cref.next);
rb_gc_mark_and_move(&RANY(obj)->as.imemo.cref.refinements);
return;
case imemo_svar:
gc_mark(objspace, RANY(obj)->as.imemo.svar.cref_or_me);
gc_mark(objspace, RANY(obj)->as.imemo.svar.lastline);
gc_mark(objspace, RANY(obj)->as.imemo.svar.backref);
gc_mark(objspace, RANY(obj)->as.imemo.svar.others);
rb_gc_mark_and_move((VALUE *)&RANY(obj)->as.imemo.svar.cref_or_me);
rb_gc_mark_and_move((VALUE *)&RANY(obj)->as.imemo.svar.lastline);
rb_gc_mark_and_move((VALUE *)&RANY(obj)->as.imemo.svar.backref);
rb_gc_mark_and_move((VALUE *)&RANY(obj)->as.imemo.svar.others);
return;
case imemo_throw_data:
gc_mark(objspace, RANY(obj)->as.imemo.throw_data.throw_obj);
rb_gc_mark_and_move((VALUE *)&RANY(obj)->as.imemo.throw_data.throw_obj);
return;
case imemo_ifunc:
gc_mark_maybe(objspace, (VALUE)RANY(obj)->as.imemo.ifunc.data);
if (!reference_updating) {
gc_mark_maybe(objspace, (VALUE)RANY(obj)->as.imemo.ifunc.data);
}
return;
case imemo_memo:
gc_mark(objspace, RANY(obj)->as.imemo.memo.v1);
gc_mark(objspace, RANY(obj)->as.imemo.memo.v2);
gc_mark_maybe(objspace, RANY(obj)->as.imemo.memo.u3.value);
rb_gc_mark_and_move((VALUE *)&RANY(obj)->as.imemo.memo.v1);
rb_gc_mark_and_move((VALUE *)&RANY(obj)->as.imemo.memo.v2);
if (!reference_updating) {
gc_mark_maybe(objspace, RANY(obj)->as.imemo.memo.u3.value);
}
return;
case imemo_ment:
mark_method_entry(objspace, &RANY(obj)->as.imemo.ment);
mark_and_move_method_entry(objspace, &RANY(obj)->as.imemo.ment, reference_updating);
return;
case imemo_iseq:
rb_iseq_mark_and_move((rb_iseq_t *)obj, false);
rb_iseq_mark_and_move((rb_iseq_t *)obj, reference_updating);
return;
case imemo_tmpbuf:
{
const rb_imemo_tmpbuf_t *m = &RANY(obj)->as.imemo.alloc;
do {
rb_gc_mark_locations(m->ptr, m->ptr + m->cnt);
} while ((m = m->next) != NULL);
if (!reference_updating) {
const rb_imemo_tmpbuf_t *m = &RANY(obj)->as.imemo.alloc;
do {
rb_gc_mark_locations(m->ptr, m->ptr + m->cnt);
} while ((m = m->next) != NULL);
}
}
return;
case imemo_ast:
rb_ast_mark(&RANY(obj)->as.imemo.ast);
rb_ast_mark_and_move(&RANY(obj)->as.imemo.ast, reference_updating);
return;
case imemo_parser_strterm:
return;
case imemo_callinfo:
return;
case imemo_callcache:
Expand All @@ -7272,15 +7301,32 @@ gc_mark_imemo(rb_objspace_t *objspace, VALUE obj)
*/
{
const struct rb_callcache *cc = (const struct rb_callcache *)obj;
if (vm_cc_super_p(cc) || vm_cc_refinement_p(cc)) {
gc_mark(objspace, (VALUE)cc->cme_);
if (reference_updating) {
if (!cc->klass) {
// already invalidated
}
else {
if (moved_or_living_object_strictly_p(objspace, cc->klass) &&
moved_or_living_object_strictly_p(objspace, (VALUE)cc->cme_)) {
UPDATE_IF_MOVED(objspace, cc->klass);
TYPED_UPDATE_IF_MOVED(objspace, struct rb_callable_method_entry_struct *, cc->cme_);
}
else {
vm_cc_invalidate(cc);
}
}
}
else {
if (vm_cc_super_p(cc) || vm_cc_refinement_p(cc)) {
gc_mark(objspace, (VALUE)cc->cme_);
}
}
}
return;
case imemo_constcache:
{
const struct iseq_inline_constant_cache_entry *ice = (struct iseq_inline_constant_cache_entry *)obj;
gc_mark(objspace, ice->value);
struct iseq_inline_constant_cache_entry *ice = (struct iseq_inline_constant_cache_entry *)obj;
rb_gc_mark_and_move(&ice->value);
}
return;
#if VM_CHECK_MODE > 0
Expand Down Expand Up @@ -7328,7 +7374,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj)
break;

case T_IMEMO:
gc_mark_imemo(objspace, obj);
gc_mark_and_move_imemo(objspace, obj, false);
return;

default:
Expand Down Expand Up @@ -10359,46 +10405,6 @@ gc_ref_update_hash(rb_objspace_t * objspace, VALUE v)
rb_hash_stlike_foreach_with_replace(v, hash_foreach_replace, hash_replace_ref, (st_data_t)objspace);
}

static void
gc_ref_update_method_entry(rb_objspace_t *objspace, rb_method_entry_t *me)
{
rb_method_definition_t *def = me->def;

UPDATE_IF_MOVED(objspace, me->owner);
UPDATE_IF_MOVED(objspace, me->defined_class);

if (def) {
switch (def->type) {
case VM_METHOD_TYPE_ISEQ:
if (def->body.iseq.iseqptr) {
TYPED_UPDATE_IF_MOVED(objspace, rb_iseq_t *, def->body.iseq.iseqptr);
}
TYPED_UPDATE_IF_MOVED(objspace, rb_cref_t *, def->body.iseq.cref);
break;
case VM_METHOD_TYPE_ATTRSET:
case VM_METHOD_TYPE_IVAR:
UPDATE_IF_MOVED(objspace, def->body.attr.location);
break;
case VM_METHOD_TYPE_BMETHOD:
UPDATE_IF_MOVED(objspace, def->body.bmethod.proc);
break;
case VM_METHOD_TYPE_ALIAS:
TYPED_UPDATE_IF_MOVED(objspace, struct rb_method_entry_struct *, def->body.alias.original_me);
return;
case VM_METHOD_TYPE_REFINED:
TYPED_UPDATE_IF_MOVED(objspace, struct rb_method_entry_struct *, def->body.refined.orig_me);
break;
case VM_METHOD_TYPE_CFUNC:
case VM_METHOD_TYPE_ZSUPER:
case VM_METHOD_TYPE_MISSING:
case VM_METHOD_TYPE_OPTIMIZED:
case VM_METHOD_TYPE_UNDEF:
case VM_METHOD_TYPE_NOTIMPLEMENTED:
break;
}
}
}

static void
gc_update_values(rb_objspace_t *objspace, long n, VALUE *values)
{
Expand All @@ -10415,93 +10421,6 @@ rb_gc_update_values(long n, VALUE *values)
gc_update_values(&rb_objspace, n, values);
}

static bool
moved_or_living_object_strictly_p(rb_objspace_t *objspace, VALUE obj)
{
return obj &&
is_pointer_to_heap(objspace, (void *)obj) &&
(is_live_object(objspace, obj) || BUILTIN_TYPE(obj) == T_MOVED);
}

static void
gc_ref_update_imemo(rb_objspace_t *objspace, VALUE obj)
{
switch (imemo_type(obj)) {
case imemo_env:
{
rb_env_t *env = (rb_env_t *)obj;
if (LIKELY(env->ep)) {
// just after newobj() can be NULL here.
TYPED_UPDATE_IF_MOVED(objspace, rb_iseq_t *, env->iseq);
UPDATE_IF_MOVED(objspace, env->ep[VM_ENV_DATA_INDEX_ENV]);
gc_update_values(objspace, (long)env->env_size, (VALUE *)env->env);
}
}
break;
case imemo_cref:
UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.cref.klass_or_self);
TYPED_UPDATE_IF_MOVED(objspace, struct rb_cref_struct *, RANY(obj)->as.imemo.cref.next);
UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.cref.refinements);
break;
case imemo_svar:
UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.svar.cref_or_me);
UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.svar.lastline);
UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.svar.backref);
UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.svar.others);
break;
case imemo_throw_data:
UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.throw_data.throw_obj);
break;
case imemo_ifunc:
break;
case imemo_memo:
UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.memo.v1);
UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.memo.v2);
break;
case imemo_ment:
gc_ref_update_method_entry(objspace, &RANY(obj)->as.imemo.ment);
break;
case imemo_iseq:
rb_iseq_mark_and_move((rb_iseq_t *)obj, true);
break;
case imemo_ast:
rb_ast_update_references((rb_ast_t *)obj);
break;
case imemo_callcache:
{
const struct rb_callcache *cc = (const struct rb_callcache *)obj;

if (!cc->klass) {
// already invalidated
}
else {
if (moved_or_living_object_strictly_p(objspace, cc->klass) &&
moved_or_living_object_strictly_p(objspace, (VALUE)cc->cme_)) {
UPDATE_IF_MOVED(objspace, cc->klass);
TYPED_UPDATE_IF_MOVED(objspace, struct rb_callable_method_entry_struct *, cc->cme_);
}
else {
vm_cc_invalidate(cc);
}
}
}
break;
case imemo_constcache:
{
const struct iseq_inline_constant_cache_entry *ice = (struct iseq_inline_constant_cache_entry *)obj;
UPDATE_IF_MOVED(objspace, ice->value);
}
break;
case imemo_parser_strterm:
case imemo_tmpbuf:
case imemo_callinfo:
break;
default:
rb_bug("not reachable %d", imemo_type(obj));
break;
}
}

static enum rb_id_table_iterator_result
check_id_table_move(VALUE value, void *data)
{
Expand Down Expand Up @@ -10754,7 +10673,7 @@ gc_update_object_references(rb_objspace_t *objspace, VALUE obj)
break;

case T_IMEMO:
gc_ref_update_imemo(objspace, obj);
gc_mark_and_move_imemo(objspace, obj, true);
return;

case T_NIL:
Expand Down

0 comments on commit c184aa8

Please sign in to comment.