Keep write-barrier status after splicing array

We don't need to remove the write-barrier protected status after
splicing an array. We can simply add it to the rememberset for marking
during the next GC.

The benchmark illustrates the performance impact on minor GC:

```
require "benchmark"

arys = 1_000_000.times.map do
  ary = Array.new(50)
  ary.insert(1, 3)
  ary
end

4.times { GC.start }

puts(Benchmark.measure do
  1000.times do
    GC.start(full_mark: false)
  end
end)
```

This branch:

```
  1.309910   0.004342   1.314252 (  1.314580)
```

Master branch:

```
 54.376091   0.219037  54.595128 ( 54.742996)
```
This commit is contained in:
Peter Zhu 2023-09-01 10:07:32 -04:00
Родитель 2ac3e9abe9
Коммит 4cc5659293
1 изменённых файлов: 8 добавлений и 3 удалений

11
array.c
Просмотреть файл

@ -2176,9 +2176,14 @@ rb_ary_splice(VALUE ary, long beg, long len, const VALUE *rptr, long rlen)
ARY_SET_LEN(ary, alen);
}
if (rlen > 0) {
if (rofs != -1) rptr = RARRAY_CONST_PTR(ary) + rofs;
/* give up wb-protected ary */
RB_OBJ_WB_UNPROTECT_FOR(ARRAY, ary);
if (rofs == -1) {
rb_gc_writebarrier_remember(ary);
}
else {
/* In this case, we're copying from a region in this array, so
* we don't need to fire the write barrier. */
rptr = RARRAY_CONST_PTR(ary) + rofs;
}
/* do not use RARRAY_PTR() because it can causes GC.
* ary can contain T_NONE object because it is not cleared.