aboutsummaryrefslogtreecommitdiffstats
path: root/iseq.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 /iseq.c
parent44b19b01e22c0e2b24e97cbcab80aee953f978fd (diff)
downloadruby-c330037c1a38cc257dbe21022fcc7b13159c2821.tar.gz
`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 ```
Diffstat (limited to 'iseq.c')
-rw-r--r--iseq.c49
1 files changed, 28 insertions, 21 deletions
diff --git a/iseq.c b/iseq.c
index 540f180e2e..7bd255a505 100644
--- a/iseq.c
+++ b/iseq.c
@@ -282,6 +282,29 @@ rb_iseq_mark_and_move_each_value(const rb_iseq_t *iseq, VALUE *original_iseq)
}
}
+static bool
+cc_is_active(const struct rb_callcache *cc, bool reference_updating)
+{
+ if (cc) {
+ if (reference_updating) {
+ cc = (const struct rb_callcache *)rb_gc_location((VALUE)cc);
+ }
+
+ if (vm_cc_markable(cc)) {
+ if (cc->klass) { // cc is not invalidated
+ const struct rb_callable_method_entry_struct *cme = vm_cc_cme(cc);
+ if (reference_updating) {
+ cme = (const struct rb_callable_method_entry_struct *)rb_gc_location((VALUE)cme);
+ }
+ if (!METHOD_ENTRY_INVALIDATED(cme)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
void
rb_iseq_mark_and_move(rb_iseq_t *iseq, bool reference_updating)
{
@@ -310,27 +333,11 @@ rb_iseq_mark_and_move(rb_iseq_t *iseq, bool reference_updating)
if (cds[i].ci) rb_gc_mark_and_move_ptr(&cds[i].ci);
- const struct rb_callcache *cc = cds[i].cc;
- if (cc) {
- if (reference_updating) {
- cc = (const struct rb_callcache *)rb_gc_location((VALUE)cc);
- }
-
- if (vm_cc_markable(cc)) {
- VM_ASSERT((cc->flags & VM_CALLCACHE_ON_STACK) == 0);
-
- const struct rb_callable_method_entry_struct *cme = vm_cc_cme(cc);
- if (reference_updating) {
- cme = (const struct rb_callable_method_entry_struct *)rb_gc_location((VALUE)cme);
- }
-
- if (cc->klass && !METHOD_ENTRY_INVALIDATED(cme)) {
- rb_gc_mark_and_move_ptr(&cds[i].cc);
- }
- else {
- cds[i].cc = rb_vm_empty_cc();
- }
- }
+ if (cc_is_active(cds[i].cc, reference_updating)) {
+ rb_gc_mark_and_move_ptr(&cds[i].cc);
+ }
+ else {
+ cds[i].cc = rb_vm_empty_cc();
}
}
}