Previously, generic ivars worked differently than the other global tables
during compaction. The other global tables had their references updated
through iteration during rb_gc_update_vm_references. Generic ivars updated
the keys when the object moved and updated the values while reference
updating the object. This is inefficient as this required one lookup for
every moved object and one lookup for every object with generic ivars.
Instead, this commit changes it to iterate over the generic ivar table to
update both the keys and values.
Depending on the allocator, `malloc_usable_size` may be very cheap or quite
expensive. On `macOS` for instance, it's about as expensive as `malloc`.
In many case we call `objspace_malloc_size` with as size we initially
requested as `hint`. The real usable size may be a few bytes bigger,
but since we only use that data to feed GC heuristics, I don't think
it's very important to be perfectly accurate.
It would make sense to call `malloc_usable_size` after growing a String
or Array to use the extra capacity, but here we don't do that, so
the call isn't worth its cost.
rb_darray_insert could trigger a GC, which would cause problems if it
freed pages while a new page was being inserted.
For example, the following script fails:
GC.stress = true
GC.auto_compact = :empty
10.times do
GC.verify_compaction_references(expand_heap: true, toward: :empty)
end
It errors out with:
'GC.verify_compaction_references': malloc: possible integer overflow (8*18446744073709551603) (ArgumentError)
If we try to use GET_PAGE_HEADER, it can trigger the read barrier. If we
try to align on the slot then we end up unlocking the heap page of a
lower memory address.
We have name fragmentation for this feature, including "shared GC",
"modular GC", and "external GC". This commit standardizes the feature
name to "modular GC" and the implementation to "GC library".
Let there be rooms for each GC implementations how to handle multi
threaded situations. They can be totally reentrant, or can have
their own mutex, or can rely on rb_thread_call_with_gvl.
In any ways the allocator (has been, but now officially is)
expected to run properly without a GVL. This means there need be
a way for them to inform the interpreter about their allocation
failures, without relying on raising exceptions.
Let them do so by returning NULL.