summaryrefslogtreecommitdiff
path: root/gc.c
diff options
context:
space:
mode:
authorRuby <test@ruby-lang.org>2023-07-26 13:39:31 +0900
committerKoichi Sasada <ko1@atdot.net>2023-07-28 10:51:11 +0900
commitc330037c1a38cc257dbe21022fcc7b13159c2821 (patch)
tree508edd219ceb6c97b83ef8888f505efc4fc95dcf /gc.c
parent44b19b01e22c0e2b24e97cbcab80aee953f978fd (diff)
`cc->cme` should not be marked.
cc is callcache. cc->klass (klass) should not be marked because if the klass is free'ed, the cc->klass will be cleared by `vm_cc_invalidate()`. cc->cme (cme) should not be marked because if cc is invalidated when cme is free'ed. - klass marks cme if klass uses cme. - caller classe's ccs->cme marks cc->cme. - if cc is invalidated (klass doesn't refer the cc), cc is invalidated by `vm_cc_invalidate()` and cc->cme is not be accessed. - On the multi-Ractors, cme will be collected with global GC so that it is safe if GC is not interleaving while accessing cc and cme. fix [Bug #19436] ```ruby 10_000.times{|i| # p i if (i%1_000) == 0 str = "x" * 1_000_000 def str.foo = nil eval "def call#{i}(s) = s.foo" send "call#{i}", str } ``` Without this patch: ``` real 1m5.639s user 0m6.637s sys 0m58.292s ``` and with this patch: ``` real 0m2.045s user 0m1.627s sys 0m0.164s ```
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/8120
Diffstat (limited to 'gc.c')
-rw-r--r--gc.c33
1 files changed, 23 insertions, 10 deletions
diff --git a/gc.c b/gc.c
index ca018b7ae1..f55fcb4fe1 100644
--- a/gc.c
+++ b/gc.c
@@ -7015,11 +7015,22 @@ gc_mark_imemo(rb_objspace_t *objspace, VALUE obj)
case imemo_callinfo:
return;
case imemo_callcache:
- {
- const struct rb_callcache *cc = (const struct rb_callcache *)obj;
- // should not mark klass here
- gc_mark(objspace, (VALUE)vm_cc_cme(cc));
- }
+ /* cc is callcache.
+ *
+ * cc->klass (klass) should not be marked because if the klass is
+ * free'ed, the cc->klass will be cleared by `vm_cc_invalidate()`.
+ *
+ * cc->cme (cme) should not be marked because if cc is invalidated
+ * when cme is free'ed.
+ * - klass marks cme if klass uses cme.
+ * - caller classe's ccs->cme marks cc->cme.
+ * - if cc is invalidated (klass doesn't refer the cc),
+ * cc is invalidated by `vm_cc_invalidate()` and cc->cme is
+ * not be accessed.
+ * - On the multi-Ractors, cme will be collected with global GC
+ * so that it is safe if GC is not interleaving while accessing
+ * cc and cme.
+ */
return;
case imemo_constcache:
{
@@ -10122,12 +10133,14 @@ gc_ref_update_imemo(rb_objspace_t *objspace, VALUE obj)
if (!is_live_object(objspace, cc->klass)) {
*((VALUE *)(&cc->klass)) = (VALUE)0;
}
- }
- if (cc->cme_) {
- TYPED_UPDATE_IF_MOVED(objspace, struct rb_callable_method_entry_struct *, cc->cme_);
- if (!is_live_object(objspace, (VALUE)cc->cme_)) {
- *((struct rb_callable_method_entry_struct **)(&cc->cme_)) = (struct rb_callable_method_entry_struct *)0;
+ // cc->cme_ is available if cc->klass is given
+
+ if (cc->cme_) {
+ TYPED_UPDATE_IF_MOVED(objspace, struct rb_callable_method_entry_struct *, cc->cme_);
+ if (!is_live_object(objspace, (VALUE)cc->cme_)) {
+ *((struct rb_callable_method_entry_struct **)(&cc->cme_)) = (struct rb_callable_method_entry_struct *)0;
+ }
}
}
}