diff options
author | Ruby <[email protected]> | 2023-07-26 13:39:31 +0900 |
---|---|---|
committer | Koichi Sasada <[email protected]> | 2023-07-28 10:51:11 +0900 |
commit | c330037c1a38cc257dbe21022fcc7b13159c2821 (patch) | |
tree | 508edd219ceb6c97b83ef8888f505efc4fc95dcf /iseq.c | |
parent | 44b19b01e22c0e2b24e97cbcab80aee953f978fd (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 'iseq.c')
-rw-r--r-- | iseq.c | 49 |
1 files changed, 28 insertions, 21 deletions
@@ -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(); } } } |