From c41c323f1a001ab62c69add4bf01c6a887641f2a Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Thu, 7 Aug 2025 15:39:45 -0700 Subject: [PATCH] Invalidate CCs when cme is invalidated in marking * Skip assertion when cc->klass is Qundef * Invalidate CCs when cme is invalidated in marking * Add additional assertions that CC references stay valid Co-authored-by: Peter Zhu --- imemo.c | 3 +++ vm_method.c | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/imemo.c b/imemo.c index 2c721ca911..30dae8d583 100644 --- a/imemo.c +++ b/imemo.c @@ -372,6 +372,9 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating) } } else { + RUBY_ASSERT(RB_TYPE_P(cc->klass, T_CLASS) || RB_TYPE_P(cc->klass, T_ICLASS)); + RUBY_ASSERT(IMEMO_TYPE_P((VALUE)cc->cme_, imemo_ment)); + rb_gc_mark_weak((VALUE *)&cc->klass); if ((vm_cc_super_p(cc) || vm_cc_refinement_p(cc))) { rb_gc_mark_movable((VALUE)cc->cme_); diff --git a/vm_method.c b/vm_method.c index 76b1c97d04..c1793c102c 100644 --- a/vm_method.c +++ b/vm_method.c @@ -30,16 +30,27 @@ mark_cc_entry_i(VALUE ccs_ptr, void *data) VM_ASSERT(vm_ccs_p(ccs)); if (METHOD_ENTRY_INVALIDATED(ccs->cme)) { + /* Before detaching the CCs from this class, we need to invalidate the cc + * since we will no longer be marking the cme on their behalf. + */ + for (int i = 0; i < ccs->len; i++) { + const struct rb_callcache *cc = ccs->entries[i].cc; + if (cc->klass == Qundef) continue; // already invalidated + VM_ASSERT(cc->klass == Qundef || vm_cc_check_cme(cc, ccs->cme)); + VM_ASSERT(!vm_cc_super_p(cc) && !vm_cc_refinement_p(cc)); + vm_cc_invalidate(cc); + } ruby_xfree(ccs); return ID_TABLE_DELETE; } else { rb_gc_mark_movable((VALUE)ccs->cme); - for (int i=0; ilen; i++) { - VM_ASSERT(vm_cc_check_cme(ccs->entries[i].cc, ccs->cme)); + for (int i = 0; i < ccs->len; i++) { + const struct rb_callcache *cc = ccs->entries[i].cc; + VM_ASSERT(cc->klass == Qundef || vm_cc_check_cme(cc, ccs->cme)); - rb_gc_mark_movable((VALUE)ccs->entries[i].cc); + rb_gc_mark_movable((VALUE)cc); } return ID_TABLE_CONTINUE; }