Граф коммитов

2520 Коммитов

Автор SHA1 Сообщение Дата
Matt Valentine-House 8792e421ce Allow pages to be sorted by pinned slot count
By compacting into slots with pinned objects first, we improve the
efficiency of compaction. As it is less likely that there will exist
pages containing only pinned objects after compaction. This will
increase the number of free pages left after compaction and enable us to
free them.

This used to be the default compaction method before it was removed
(inadvertently?) during the introduction of auto_compaction.

This commit will sort the pages by the pinned slot count at the start of
a major GC that has been triggered by explicitly calling GC.compact (and
thus setting objspace->flags.during_compaction).

It works using the same method by which we sort the heap by empty slot
count during GC.verify_compaction_references.
2023-09-18 14:34:38 +01:00
Matt Valentine-House 404a1c032a Move heap sorting into the main GC loop
Previously it was only being sorted during the verify compaction
references stage - so would only happen during testing.

This commit allows us to sort the heap prior to each explicit GC.compact
run
2023-09-18 14:34:38 +01:00
Matt Valentine-House d3852f71e4 Enable different heap sort methods during compaction
pass the sorting function in as a function pointer so we don't always
sort by how empty a page is
2023-09-18 14:34:38 +01:00
Peter Zhu 4aac7b1a9a Another try to fix build in emscripten
malloc_trim is defined in emscripten/emmalloc.h on emscripten.
2023-09-16 13:24:41 -04:00
Peter Zhu 209d5f8482 Fix malloc_trim on emscripten
```
gc.c:9746:5: error: implicit declaration of function 'malloc_trim' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
    malloc_trim(0);
    ^
```

http://rubyci.s3.amazonaws.com/crossruby/crossruby-master-wasm32_emscripten/log/20230916T104311Z.fail.html.gz
2023-09-16 09:08:55 -04:00
Jean Boussier c3ef7a528b Fix malloc_trim() on wasm32
```
compiling gc.c
gc.c:9746:5: error: implicit declaration of function 'malloc_trim' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
    malloc_trim(0);
    ^
1 error generated.
```
2023-09-16 09:52:46 +02:00
Adam Hess 4d86d932fd Free all heap pages at shutdown
previously heap_allocated_pages was decremented from heap_page_free causing only half the heap pages to be freed at shutdown
2023-09-15 13:24:32 -04:00
Jean Boussier efe2822708 Process.warmup: invoke `malloc_trim` if available
Similar to releasing free GC pages, releasing free malloc pages
reduce the amount of page faults post fork.
2023-09-15 17:45:21 +02:00
Peter Zhu b90272b3b6 Fix typo in gc.c 2023-09-12 11:20:22 -04:00
John Hawthorn 094f336a27 GC: Only force alloc slowpath for NEWOBJ hook
Previously, configuring any GC event hook would cause all allocations to
go through the newobj slowpath. We should only need to do that when the
newobj specifically is subscribed to.

This renames flags.has_hook to flags.has_newobj_hook, to make this new
usage clear. newobj_of0 was the only place which previously checked this
flag.
2023-09-07 13:51:56 -07:00
Peter Zhu 12102d101a Fix crash in WeakMap during compaction
WeakMap can crash during compaction because the st_insert could allocate
memory.
2023-09-06 14:20:23 -04:00
Peter Zhu 6778d2c582 Support freeing the lowest memory address page
This should help fix the following flaky test:

```
  1) Failure:
TestProcess#test_warmup_frees_pages [test/ruby/test_process.rb:2751]:
<0> expected but was
<1>.
```
2023-09-06 08:43:14 -04:00
Peter Zhu 9a8398a18f Introduce rb_gc_remove_weak
If we're during incremental marking, then Ruby code can execute that
deallocates certain memory buffers that have been called with
rb_gc_mark_weak, which can cause use-after-free bugs.
2023-09-05 14:32:15 -04:00
Peter Zhu ab9d1910ef Rename shady to uncollectible_wb_unprotected
The term "shady object" was renamed to "uncollectible write barrier
unprotected object", so rename `has_uncollectible_shady_objects` to
`has_uncollectible_wb_unprotected_objects` for consistency.
2023-09-05 10:55:23 -04:00
Peter Zhu 7a930cf0e4 Pool more slots for large size pools
We always sweep at least 2048 slots per sweep step, but only pool one
page. For large size pools, 2048 slots is many pages but one page is
very few slots. This commit changes it so that at least 1024 slots are
placed in the pooled pages per sweep step.
2023-09-05 10:52:35 -04:00
Peter Zhu ef65183692 Add check for T_NONE in rb_gc_mark_weak
This commit adds a check for T_NONE in rb_gc_mark_weak, just like
gc_mark_ptr. This will help debugging.
2023-09-05 09:27:11 -04:00
Peter Zhu bead539650 Incrementally mark even if we have free pages
We move all pooled pages to free pages at the start of incremental
marking, so we shouldn't run incremental marking only when we have run
out of free pages. This causes incremental marking to always complete
in a single step.
2023-09-01 11:58:50 -04:00
Peter Zhu 771576f021 Skip weak references to old objects in minor GC
If we are in a minor GC and the object to mark is old, then the old
object should already be marked and cannot be reclaimed in this GC cycle
so we don't need to add it to the weak refences list.
2023-09-01 09:31:59 -04:00
Matt Valentine-House 945945dad4 Remove gc_mark_values
Now that gc_mark_values and rb_gc_mark_values are identical, we should
remove one.
2023-08-31 19:31:18 +01:00
Matt Valentine-House 322548180d Prevent rb_gc_mark_values from pinning objects
This is an internal only function not exposed to the C extension API.
It's only use so far is from rb_vm_mark, where it's used to mark the
values in the vm->trap_list.cmd array.

There shouldn't be any reason why these cannot move.

This commit allows them to move by updating their references during the
reference updating step of compaction.

To do this we've introduced another internal function
rb_gc_update_values as a partner to rb_gc_mark_values.

This allows us to refactor rb_gc_mark_values to not pin
2023-08-31 19:31:18 +01:00
Peter Zhu 4f0d58260a Correctly calculate initial pages
The old algorithm could calculate an undercount for the initial pages
due to two issues:

1. It did not take into account that some heap pages will have one less
   slot due to alignment. It assumed that every heap page would be able
   to be fully filled with slots. Pages that are unaligned with the slot
   size will lose one slot. The new algorithm assumes that every page
   will be unaligned.
2. It performed integer division, which truncates down. This means that
   the number of pages might not actually satisfy the number of slots.

This can cause the heap to grow in `gc_sweep_finish_size_pool` after
allocating all of the allocatable pages because the total number of
slots would be less than the initial configured number of slots.
2023-08-31 09:28:31 -04:00
Peter Zhu 0aa404b957 Change heap init environment variable names
This commit changes RUBY_GC_HEAP_INIT_SIZE_{40,80,160,320,640}_SLOTS to
RUBY_GC_HEAP_{0,1,2,3,4}_INIT_SLOTS. This is easier to use because the
user does not need to determine the slot sizes (which can vary between
32 and 64 bit systems). They now just use the heap names
(`GC.stat_heap.keys`).
2023-08-30 19:37:11 -04:00
Peter Zhu fd0df1f8c6 Fix growth in minor GC when we have initial slots
If initial slots is set, then during a minor GC, if we have allocatable
pages but the heap is mostly full, then we will set `grow_heap` to true
since `total_slots` does not count allocatable pages so it will be less
than `init_slots`. This can cause `allocatable_pages` to grow to much
higher than desired since it will appear that the heap is mostly full.
2023-08-28 18:01:29 -04:00
Peter Zhu 5485680244 Expose RVALUE_OLD_AGE in GC::INTERNAL_CONSTANTS 2023-08-28 18:01:29 -04:00
Peter Zhu b7237e3bbd Free all empty heap pages in Process.warmup
This commit adds `free_empty_pages` which frees all empty heap pages and
moves the number of pages freed to the allocatable pages counter. This
is used in Process.warmup to improve performance because page
invalidation from copy-on-write is slower than allocating a new page.
2023-08-27 09:39:29 -04:00
Peter Zhu 9ea9f99248 [Feature #19785] Deprecate RUBY_GC_HEAP_INIT_SLOTS
This environment variable is replaced by
`RUBY_GC_HEAP_INIT_SIZE_%d_SLOTS`, so it doesn't make sense to keep it.
2023-08-25 21:50:56 -04:00
Peter Zhu 2091bf9493 Expose stats about weak references
[Feature #19783]

This commit adds stats about weak references to `GC.latest_gc_info`.
It adds the following two keys:

- `weak_references_count`: number of weak references registered during
  the last GC.
- `retained_weak_references_count`: number of weak references that
  survived the last GC.
2023-08-25 09:01:21 -04:00
Peter Zhu bfb395c620 Implement weak references in the GC
[Feature #19783]

This commit adds support for weak references in the GC through the
function `rb_gc_mark_weak`. Unlike strong references, weak references
does not mark the object, but rather lets the GC know that an object
refers to another one. If the child object is freed, the pointer from
the parent object is overwritten with `Qundef`.

Co-Authored-By: Jean Boussier <byroot@ruby-lang.org>
2023-08-25 09:01:21 -04:00
eileencodes b92d599eec Fix typo in anonymous class string
If anonymous was shorted it should be `anon` not `annon`. Fixes typo in
APPEND_S for anonymous classes.
2023-08-23 13:09:18 +09:00
Peter Zhu 5db8b9b366 Move total_freed_objects to size pool
This commit moves the `total_freed_objects` statistic to the size pool
which allows for `total_freed_objects` key in `GC.stat_heap`.
2023-08-17 15:53:00 -04:00
Peter Zhu 52506cbf51 Move total_allocated_objects to size pool
This commit moves the `total_allocated_objects` statistic to the size
pool which allows for `total_allocated_objects` key in `GC.stat_heap`.
2023-08-17 15:53:00 -04:00
Takashi Kokubun e210b899dc
Move the PC regardless of the leaf flag (#8232)
Co-authored-by: Alan Wu <alansi.xingwu@shopify.com>
2023-08-16 20:28:33 -07:00
Peter Zhu 0f94e65359 Add stat force_incremental_marking_finish_count
This commit adds key force_incremental_marking_finish_count to
GC.stat_heap. This statistic returns the number of times the size pool
has forced incremental marking to finish due to running out of slots.
2023-08-15 15:18:05 -04:00
Peter Zhu 300bc14589 [DOC] Improve some GC docs 2023-08-15 08:54:27 -04:00
Peter Zhu 74b9c7d207 Remove wrapper functions of RVALUE_REMEMBERED
Functions rgengc_remembered, rgengc_remembered_sweep, and
rgengc_remembersetbits_get are just wrappers of RVALUE_REMEMBERED and
doesn't do much more. We can remove all those and use RVALUE_REMEMBERED
directly instead.
2023-08-08 09:44:13 -04:00
Nobuyoshi Nakada acd27e3ec3
Move `GC_CAN_COMPILE_COMPACTION` definition before used 2023-08-06 18:45:40 +09:00
Peter Zhu 4b45b2764b Don't check stack for moved after compaction
We don't need to check stack for moved objects after compaction because
the mutator cannot run between marking the stack and the end of
compaction. However, the stack may have moved objects leftover from
marking and sweeping phases. This means that their pages will be
invalidated and all objects moved back. We don't need to move these
objects back.

This also fixes the issue on Windows where some compaction tests
sometimes fail due to the page of the object being invalidated.
2023-08-04 09:13:57 -04:00
Peter Zhu c65856d44f Remove unneeded function prototype
Function prototype for gc_mode_transition is not needed as it's not
used before the implementation.
2023-08-03 11:12:07 -04:00
Peter Zhu c01b17f7fc Fix default value of global_init_slots
Not setting a value to global_init_slots causes get_envparam_size to
output a broken default value.
2023-07-31 15:12:20 -04:00
Peter Zhu b98838b65c Store initial slots per size pool
This commit stores the initial slots per size pool, configured with
the environment variables `RUBY_GC_HEAP_INIT_SIZE_%d_SLOTS`. This
ensures that the configured initial slots remains a low bound for the
number of slots in the heap, which can prevent heaps from thrashing in
size.
2023-07-31 11:46:53 -04:00
Koichi Sasada cfd7729ce7 use inline cache for refinements
From Ruby 3.0, refined method invocations are slow because
resolved methods are not cached by inline cache because of
conservertive strategy. However, `using` clears all caches
so that it seems safe to cache resolved method entries.

This patch caches resolved method entries in inline cache
and clear all of inline method caches when `using` is called.

fix [Bug #18572]

```ruby
 # without refinements

class C
  def foo = :C
end

N = 1_000_000

obj = C.new
require 'benchmark'
Benchmark.bm{|x|
  x.report{N.times{
    obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
    obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
    obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
    obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
  }}
}

_END__
              user     system      total        real
master    0.362859   0.002544   0.365403 (  0.365424)
modified  0.357251   0.000000   0.357251 (  0.357258)
```

```ruby
 # with refinment but without using

class C
  def foo = :C
end

module R
  refine C do
    def foo = :R
  end
end

N = 1_000_000

obj = C.new
require 'benchmark'
Benchmark.bm{|x|
  x.report{N.times{
    obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
    obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
    obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
    obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
  }}
}
__END__
               user     system      total        real
master     0.957182   0.000000   0.957182 (  0.957212)
modified   0.359228   0.000000   0.359228 (  0.359238)
```

```ruby
 # with using

class C
  def foo = :C
end

module R
  refine C do
    def foo = :R
  end
end

N = 1_000_000

using R

obj = C.new
require 'benchmark'
Benchmark.bm{|x|
  x.report{N.times{
    obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
    obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
    obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
    obj.foo; obj.foo; obj.foo; obj.foo; obj.foo;
  }}
}
2023-07-31 17:13:43 +09:00
Koichi Sasada 36023d5cb7 mark `cc->cme_` if it is for `super`
`vm_search_super_method()` makes orphan CCs (they are not connected
from ccs) and `cc->cme_` can be collected before without marking.
2023-07-31 14:04:31 +09:00
Koichi Sasada 087a2deccf check `cc->*` liveness strictly
to fix SEGV like
http://ci.rvm.jp/results/trunk-repeat20-asserts@ruby-sp2-docker/4664004
```
/tmp/ruby/build/trunk-repeat20-asserts/libruby.so.3.3(sigsegv+0x4f) [0x7fcb0343e7df] /tmp/ruby/src/trunk-repeat20-asserts/signal.c:920
/lib/x86_64-linux-gnu/libc.so.6(0x7fcb02e4d520) [0x7fcb02e4d520]
/tmp/ruby/build/trunk-repeat20-asserts/libruby.so.3.3(RB_SPECIAL_CONST_P+0x13) [0x7fcb03311ea3] /tmp/ruby/src/trunk-repeat20-asserts/include/ruby/internal/special_consts.h:329
/tmp/ruby/build/trunk-repeat20-asserts/libruby.so.3.3(RB_BUILTIN_TYPE) /tmp/ruby/src/trunk-repeat20-asserts/include/ruby/internal/value_type.h:183
/tmp/ruby/build/trunk-repeat20-asserts/libruby.so.3.3(gc_object_moved_p) /tmp/ruby/src/trunk-repeat20-asserts/gc.c:1624
/tmp/ruby/build/trunk-repeat20-asserts/libruby.so.3.3(gc_object_moved_p+0xe) [0x7fcb0331ed16] /tmp/ruby/src/trunk-repeat20-asserts/include/ruby/internal/special_consts.h:329
/tmp/ruby/build/trunk-repeat20-asserts/libruby.so.3.3(gc_ref_update_imemo) /tmp/ruby/src/trunk-repeat20-asserts/gc.c:10132
/tmp/ruby/build/trunk-repeat20-asserts/libruby.so.3.3(gc_update_object_references) /tmp/ruby/src/trunk-repeat20-asserts/gc.c:10411
/tmp/ruby/build/trunk-repeat20-asserts/libruby.so.3.3(gc_ref_update+0xab) [0x7fcb0331fcbb] /tmp/ruby/src/trunk-repeat20-asserts/gc.c:10570
/tmp/ruby/build/trunk-repeat20-asserts/libruby.so.3.3(gc_update_references) /tmp/ruby/src/trunk-repeat20-asserts/gc.c:10604
/tmp/ruby/build/trunk-repeat20-asserts/libruby.so.3.3(gc_compact_finish) /tmp/ruby/src/trunk-repeat20-asserts/gc.c:5425
/tmp/ruby/build/trunk-repeat20-asserts/libruby.so.3.3(gc_sweep_compact) /tmp/ruby/src/trunk-repeat20-asserts/gc.c:8476
/tmp/ruby/build/trunk-repeat20-asserts/libruby.so.3.3(gc_sweep) /tmp/ruby/src/trunk-repeat20-asserts/gc.c:6040
/tmp/ruby/build/trunk-repeat20-asserts/libruby.so.3.3(gc_start+0xe25) [0x7fcb03325795] /tmp/ruby/src/trunk-repeat20-asserts/gc.c:9323
/tmp/ruby/build/trunk-repeat20-asserts/libruby.so.3.3(rb_multi_ractor_p+0x0) [0x7fcb03326108] /tmp/ruby/src/trunk-repeat20-asserts/gc.c:9208
/tmp/ruby/build/trunk-repeat20-asserts/libruby.so.3.3(rb_vm_lock_leave) /tmp/ruby/src/trunk-repeat20-asserts/vm_sync.h:92
/tmp/ruby/build/trunk-repeat20-asserts/libruby.so.3.3(garbage_collect) /tmp/ruby/src/trunk-repeat20-asserts/gc.c:9210
/tmp/ruby/build/trunk-repeat20-asserts/libruby.so.3.3(rbimpl_atomic_exchange+0x0) [0x7fcb033262b9] /tmp/ruby/src/trunk-repeat20-asserts/gc.c:9646
/tmp/ruby/build/trunk-repeat20-asserts/libruby.so.3.3(gc_finalize_deferred) /tmp/ruby/src/trunk-repeat20-asserts/gc.c:4345
/tmp/ruby/build/trunk-repeat20-asserts/libruby.so.3.3(gc_start_internal) /tmp/ruby/src/trunk-repeat20-asserts/gc.c:9647
/tmp/ruby/build/trunk-repeat20-asserts/libruby.so.3.3(gc_compact) /tmp/ruby/src/trunk-repeat20-asserts/gc.c:10748
```
2023-07-30 08:11:53 +09:00
Koichi Sasada 7a7aba755d check liveness of cc->klass and cc->cme_
`cc->klass` and `cc->cme_` can be free'ed while last marking
so that it should be checked bofore updating the pointers.

Note that `T_MOVED` is living, but `is_live_object()` returns false.
2023-07-29 14:25:15 +09:00
ko1 6dc15cc889 do not clear cme but invalidate cc
To invalidate a cc, we need to clear cc->klass by `vm_cc_invalidate()`.
I hope this patch fix the CI failures.
2023-07-29 09:06:14 +09:00
Ruby c330037c1a `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
```
2023-07-28 10:51:11 +09:00
Jean Boussier 9b405a18be Process.warmup: precompute strings coderange
This both save time for when it will be eventually needed,
and avoid mutating heap pages after a potential fork.

Instrumenting some large Rails app, I've witnessed up to
58% of String instances having their coderange still unknown.
2023-07-26 11:41:23 +02:00
Kunshan Wang 639aa76e82
Embed struct rmatch into GC slot (#8097) 2023-07-20 14:17:38 -04:00
Matt Valentine-House dd8372b3f3 cvc table entries can move 2023-07-20 13:38:58 +01:00
Peter Zhu 4c03eab1aa Lazily allocate pages at boot
We can just set alloctable pages for the first size pool rather than
eagerly allocating pages.
2023-07-18 14:52:37 -04:00
Jean Boussier fa30b99c34 Implement Process.warmup
[Feature #18885]

For now, the optimizations performed are:

  - Run a major GC
  - Compact the heap
  - Promote all surviving objects to oldgen

Other optimizations may follow.
2023-07-17 11:20:15 +02:00
Peter Zhu 4e0b287912 Remove RGENGC_OLD_NEWOBJ_CHECK
The code doesn't compile, so probably nobody is using this.
2023-07-14 13:53:34 -04:00
Peter Zhu 914b657a2b Remove unused branch in write barrier
The branch doesn't compile, so it's probably not used.
2023-07-14 13:53:20 -04:00
Peter Zhu 3223181284 Remove RARRAY_CONST_PTR_TRANSIENT
RARRAY_CONST_PTR now does the same things as RARRAY_CONST_PTR_TRANSIENT.
2023-07-13 14:48:14 -04:00
Matt Valentine-House 6a62b9b200 Remove unused forward declarations 2023-07-13 15:30:33 +01:00
Peter Zhu 1e7b67f733 [Feature #19730] Remove transient heap 2023-07-13 09:27:33 -04:00
Matt Valentine-House d426343418 Store object age in a bitmap
Closes [Feature #19729]

Previously 2 bits of the flags on each RVALUE are reserved to store the
number of GC cycles that each object has survived. This commit
introduces a new bit array on the heap page, called age_bits, to store
that information instead.

This patch still reserves one of the age bits in the flags (the old
FL_PROMOTED0 bit, now renamed FL_PROMOTED).

This is set to 0 for young objects and 1 for old objects, and is used as
a performance optimisation for the write barrier. Fetching the age_bits
from the heap page and doing the required math to calculate if the
object was old or not would slow down the write barrier. So we keep this
bit synced in the flags for fast access.
2023-07-13 09:21:36 +01:00
Nobuyoshi Nakada 5204ad56e1
Compile debugging code for stress to class always 2023-06-30 23:59:04 +09:00
Peter Zhu 58386814a7 Don't check for null pointer in calls to free
According to the C99 specification section 7.20.3.2 paragraph 2:

> If ptr is a null pointer, no action occurs.

So we do not need to check that the pointer is a null pointer.
2023-06-30 09:13:31 -04:00
Peter Zhu c3dc9fcc70 Fix heap growth in GC.verify_compaction_references
We should grow by at least gc_params.heap_init_slots, but the previous
calculation was incorrect.
2023-06-06 10:18:50 -04:00
eileencodes 40f090f433 Revert "Revert "Fix cvar caching when class is cloned""
This reverts commit 10621f7cb9.

This was reverted because the gc integrity build started failing. We
have figured out a fix so I'm reopening the PR.

Original commit message:

Fix cvar caching when class is cloned

The class variable cache that was added in
ruby#4544 changed the behavior of class
variables on cloned classes. As reported when a class is cloned AND a
class variable was set, and the class variable was read from the
original class, reading a class variable from the cloned class would
return the value from the original class.

This was happening because the IC (inline cache) is stored on the ISEQ
which is shared between the original and cloned class, therefore they
share the cache too.

To fix this we are now storing the `cref` in the cache so that we can
check if it's equal to the current `cref`. If it's different we don't
want to read from the cache. If it's the same we do. Cloned classes
don't share the same cref with their original class.

This will need to be backported to 3.1 in addition to 3.2 since the bug
exists in both versions.

We also added a marking function which was missing.

Fixes [Bug #19379]

Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
2023-06-05 11:11:12 -07:00
Aaron Patterson 10621f7cb9
Revert "Fix cvar caching when class is cloned"
This reverts commit 77d1b08247.
2023-06-01 14:55:36 -07:00
eileencodes 77d1b08247 Fix cvar caching when class is cloned
The class variable cache that was added in
https://github.com/ruby/ruby/pull/4544 changed the behavior of class
variables on cloned classes. As reported when a class is cloned AND a
class variable was set, and the class variable was read from the
original class, reading a class variable from the cloned class would
return the value from the original class.

This was happening because the IC (inline cache) is stored on the ISEQ
which is shared between the original and cloned class, therefore they
share the cache too.

To fix this we are now storing the `cref` in the cache so that we can
check if it's equal to the current `cref`. If it's different we don't
want to read from the cache. If it's the same we do. Cloned classes
don't share the same cref with their original class.

This will need to be backported to 3.1 in addition to 3.2 since the bug
exists in both versions.

We also added a marking function which was missing.

Fixes [Bug #19379]

Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
2023-06-01 08:52:48 -07:00
Peter Zhu e87f6c899e Don't immediately promote children of old objects
[Feature #19678]

References from an old object to a write barrier protected young object
will not immediately promote the young object. Instead, the young object
will age just like any other object, meaning that it has to survive
three collections before being promoted to the old generation.
References from an old object to a write barrier unprotected object will
place the parent object in the remember set for marking during minor
collections. This allows the child object to be reclaimed in minor
collections at the cost of increased time for minor collections.

On one of [Shopify's highest traffic Ruby apps, Storefront
Renderer](https://shopify.engineering/how-shopify-reduced-storefront-response-times-rewrite),
we saw significant improvements after deploying this feature in
production. We compare the GC time and response time of web workers that
have the original behaviour (non-experimental group) and this new
behaviour (experimental group). We see that with this feature we spend
significantly less time in the GC, 0.81x on average, 0.88x on p99, and
0.45x on p99.9.

This translates to improvements in average response time (0.96x) and p99
response time (0.92x).
2023-05-25 08:56:22 -04:00
Peter Zhu a23ae56c4d Add REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO
[Feature #19571]

This commit adds the environment variable
`RUBY_GC_HEAP_REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO` which is
used to calculate the `remembered_wb_unprotected_objects_limit` using a
ratio of `old_objects`. This should improve performance by reducing
major GC because, in a major GC, we mark all of the old objects, so we
should have more uncollectible WB unprotected objects before starting a
major GC. The default has been set to 0.01 (1% of old objects).

On one of [Shopify's highest traffic Ruby apps, Storefront Renderer](https://shopify.engineering/how-shopify-reduced-storefront-response-times-rewrite),
we saw significant improvements after deploying this patch in
production. In the graphs below, we have the `tuned` group which uses
`RUBY_GC_HEAP_REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO=0.01` (the
default value), and an `untuned` group, which turns this feature off
with `RUBY_GC_HEAP_REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO=0`. We
see that the tuned group spends significantly less time in GC, on
average 0.67x of the time compared to the untuned group and 0.49x for
p99. We see this improvement in GC time translate to improvements in
response times. The average response time is now 0.96x of the time
compared to the untuned group and 0.86x for p99.

https://user-images.githubusercontent.com/15860699/229559078-e23e8ce4-5f1f-4a2f-b5ef-5769f92b8c70.png
2023-05-24 12:11:48 -04:00
Jean Boussier 85b4cd7cf8
gc.c: get rid of unused objspace parameters (#7853) 2023-05-24 15:14:46 +02:00
Nobuyoshi Nakada 8d242a33af
`rb_bug` prints a newline after the message 2023-05-20 21:43:30 +09:00
Peter Zhu cea9c30fa5 Move ar_hint to ar_table_struct
This allows Hashes with ST tables to fit int he 80 byte size pool.
2023-05-17 09:19:40 -04:00
Peter Zhu 0938964ba1 Implement Hash ST tables on VWA 2023-05-17 09:19:40 -04:00
Peter Zhu 5199f2aaf9 Implement Hash AR tables on VWA 2023-05-17 09:19:40 -04:00
Ian Ker-Seymer 2f9f44f077
Ensure the VM is alive before accessing objspace in C API (Feature #19627)
[Feature #19627]
2023-05-04 08:48:34 +02:00
Peter Zhu a0d1069e03 Make classes embedded on 32 bit
Classes are now exactly 80 bytes when embedded, which perfectly fits the
3rd size pool on 32 bit systems.
2023-04-16 11:06:31 -04:00
Nobuyoshi Nakada 5944a31614
[DOC] Update sample callback of `rb_objspace_each_objects`
* refine liveness check
* fix missing closing brace
2023-04-15 11:48:11 +09:00
Peter Zhu 91dcce5ed1 Change max_iv_count to type attr_index_t
max_iv_count is calculated from next_iv_index of the shape, which is of
type attr_index_t, so we can also make max_iv_count of type
attr_index_t.
2023-04-11 15:02:44 -04:00
Peter Zhu b4571097df Enable 5 size pools on 32 bit systems
This commit will allow 32 bit systems to take advantage of VWA.
2023-04-11 11:25:12 -04:00
git 84ce6fc873 * expand tabs. [ci skip]
Please consider using misc/expand_tabs.rb as a pre-commit hook.
2023-04-07 04:43:21 +00:00
Nobuyoshi Nakada 4adcfc8cd7
[Bug #19584] [DOC] Tweek description of `rb_gc_register_address` 2023-04-07 13:42:58 +09:00
Peter Zhu bccec7fb46 Fix crash in rb_gc_register_address
[Bug #19584]

Some C extensions pass a pointer to a global variable to
rb_gc_register_address. However, if a GC is triggered inside of
rb_gc_register_address, then the object could get swept since it does
not exist on the stack.
2023-04-06 13:19:19 -04:00
Matt Valentine-House 026321c5b9 [Feature #19474] Refactor NEWOBJ macros
NEWOBJ_OF is now our canonical newobj macro. It takes an optional ec
2023-04-06 11:07:16 +01:00
Matt Valentine-House b0297feb1f Remove newobj_of_cr
We can just make newobj_of take a ractor
2023-04-06 11:07:16 +01:00
Mike Dalessio 52e571fa72 Ensure ruby_xfree won't segfault if called after vm_destruct
[Bug #19580]

The real-world scenario motivating this change is libxml2's pthread
code which uses `pthread_key_create` to set up a destructor that is
called at thread exit to free thread-local storage.

There is a small window of time -- after ruby_vm_destruct but before
the process exits -- in which a pthread may exit and the destructor is
called, leading to a segfault.

Please note that this window of time may be relatively large if
`atexit` is being used.
2023-04-05 12:57:32 -04:00
Peter Zhu 1da2e7fca3
[Feature #19579] Remove !USE_RVARGC code (#7655)
Remove !USE_RVARGC code

[Feature #19579]

The Variable Width Allocation feature was turned on by default in Ruby
3.2. Since then, we haven't received bug reports or backports to the
non-Variable Width Allocation code paths, so we assume that nobody is
using it. We also don't plan on maintaining the non-Variable Width
Allocation code, so we are going to remove it.
2023-04-04 17:30:06 -04:00
Aaron Patterson 8525603c72
Revert "Fix transient heap mode"
This reverts commit 87253d047c.

Revert "Implement `Process.warmup`"

This reverts commit ba6ccd8714.
2023-04-04 12:59:14 -07:00
Aaron Patterson 87253d047c Fix transient heap mode
Make sure the transient heap is in the right mode when we finish warming
the heap.  Also ensure the GC isn't allowed to run while we iterate and
mutate the heap.
2023-04-04 19:49:08 +02:00
Jean Boussier ba6ccd8714 Implement `Process.warmup`
[Feature #18885]

For now, the optimizations performed are:

  - Run a major GC
  - Compact the heap
  - Promote all surviving objects to oldgen

Other optimizations may follow.
2023-04-04 19:49:08 +02:00
Koichi Sasada 66755164aa add `RUBY_DEBUG_LOG` fo `each_machine_stack_value` 2023-03-31 17:27:56 +09:00
Peter Zhu 417b1a3644 Fix memory leak for iclass
[Bug #19550]

If !RCLASS_EXT_EMBEDDED (e.g. 32 bit systems) then the rb_classext_t is
allocated throug malloc so it must be freed.

The issue can be seen in the following script:

```
20.times do
  100_000.times do
    mod = Module.new
    Class.new do
      include mod
    end
  end

  # Output the Resident Set Size (memory usage, in KB) of the current Ruby process
  puts `ps -o rss= -p #{$$}`
end
```

Before this fix, the max RSS is 280MB, while after this change, it's
30MB.
2023-03-28 08:20:06 -04:00
Aaron Patterson 54dbd8bea8 Use an st table for "too complex" objects
st tables will maintain insertion order so we can marshal dump / load
objects with instance variables in the same order they were set on that
particular instance

[ruby-core:112926] [Bug #19535]

Co-Authored-By: Jemma Issroff <jemmaissroff@gmail.com>
2023-03-20 13:54:18 -07:00
Matt Valentine-House 7142328a94 [Feature #19406] Allow declarative definition of references
When using rb_data_type_struct to wrap a C struct, that C struct can
contain VALUE references to other Ruby objects.

If this is the case then one must also define dmark and optionally
dcompact callbacks in order to allow these objects to be correctly
handled by the GC. This is suboptimal as it requires GC related logic to
be implemented by extension developers. This can be a cause of subtle
bugs when references are not marked of updated correctly inside these
callbacks.

This commit provides an alternative approach, useful in the simple case
where the C struct contains VALUE members (ie. there isn't any
conditional logic, or data structure manipulation required to traverse
these references).

In this case references can be defined using a declarative syntax
as a list of edges (or, pointers to references).

A flag can be set on the rb_data_type_struct to notify the GC that
declarative references are being used, and a list of those references
can be assigned to the dmark pointer instead of a function callback, on
the rb_data_type_struct.

Macros are also provided for simple declaration of the reference list,
and building edges.

To avoid having to also find space in the struct to define a length for
the references list, I've chosed to always terminate the references list
with RUBY_REF_END - defined as UINTPTR_MAX. My assumption is that no
single struct will ever be large enough that UINTPTR_MAX is actually a
valid reference.
2023-03-17 19:20:40 +00:00
Peter Zhu a206ee6709 Assume that FL_FINALIZE is in finalizer_table
If the flag FL_FINALIZE is set, then it's guaranteed to be in the
finalizer_table, so we can directly assume that without checking.
2023-03-17 11:12:45 -04:00
Matt Valentine-House 90d3bbb52b [Feature #19442] Remove GC_ENABLE_INCREMENTAL_MARK
Ruby doesn't compile when this is disabled, and it's not tested on CI.
We should remove it.

Co-Authored-By: Peter Zhu <peter@peterzhu.ca>
2023-03-16 09:32:08 +00:00
Matt Valentine-House b3a271665b [Feature #19442] Remove USE_RINCGC flag
Ruby doesn't compile when this is set to 0. Let's remove it.
2023-03-16 09:32:08 +00:00
pkubaj 4e6c956741 Use __builtin_ppc_get_timebase on POWER with clang 2023-03-14 10:42:42 +09:00
Peter Zhu d0b8bdb392 Remove duplicate code in gc_marks_finish
There is an identical block a few lines down that does the exact same
thing.
2023-03-10 13:13:34 -05:00
Aaron Patterson 365fed6369
Revert "Allow classes and modules to become too complex"
This reverts commit 69465df424.
2023-03-10 08:50:43 -08:00
Peter Zhu f98a7fd28d Move WeakMap and WeakKeyMap code to weakmap.c
These classes don't belong in gc.c as they're not actually part of the
GC. This commit refactors the code by moving all the code into a
weakmap.c file.
2023-03-10 09:32:10 -05:00
HParker 69465df424 Allow classes and modules to become too complex
This makes the behavior of classes and modules when there are too many instance variables match the behavior of objects with too many instance variables.
2023-03-09 15:34:49 -08:00
KJ Tsanaktsidis 7bd7aee02e Fix interpreter crash caused by RUBY_INTERNAL_EVENT_NEWOBJ + Ractors
When a Ractor is created whilst a tracepoint for
RUBY_INTERNAL_EVENT_NEWOBJ is active, the interpreter crashes. This is
because during the early setup of the Ractor, the stdio objects are
created, which allocates Ruby objects, which fires the tracepoint.
However, the tracepoint machinery tries to dereference the control frame
(ec->cfp->pc), which isn't set up yet and so crashes with a null pointer
dereference.

Fix this by not firing GC tracepoints if cfp isn't yet set up.
2023-03-09 09:46:14 +01:00
Peter Zhu e1bd45624c Fix crash when allocating classes with newobj hook
We need to zero out the whole slot when running the newobj hook for a
newly allocated class because the slot could be filled with garbage,
which would cause a crash if a GC runs inside of the newobj hook.

For example, the following script crashes:

```
require "objspace"

GC.stress = true

ObjectSpace.trace_object_allocations {
  100.times do
    Class.new
  end
}
```

[Bug #19482]
2023-03-08 08:47:18 -05:00
Nobuyoshi Nakada 00d6772e40
Adjust styles [ci skip] 2023-03-08 14:02:46 +09:00
Peter Zhu c78138abd3 Add function rb_data_free
This commit adds a function rb_data_free used by obj_free and
rb_objspace_call_finalizer to free T_DATA objects. This change also
means that RUBY_TYPED_FREE_IMMEDIATELY objects can be freed immediately
in rb_objspace_call_finalizer rather than being created into a zombie.
2023-03-07 08:28:03 -05:00
Takashi Kokubun 23ec248e48 s/mjit/rjit/ 2023-03-06 23:44:01 -08:00
Takashi Kokubun 233ddfac54 Stop exporting symbols for MJIT 2023-03-06 21:59:23 -08:00
Peter Zhu a1758fbd7f Crash when malloc during GC
This feature was introduced in commit 2ccf6e5, but I realized that
using rb_warn is a bad idea because it allocates objects, which causes
a different crash ("object allocation during garbage collection phase").
We should just hard crash here instead.
2023-03-06 09:09:03 -05:00
John Bampton 2f7270c681
Fix spelling (#7389) 2023-02-27 09:56:06 -08:00
Peter Zhu fa1eb31fca [ci skip] Add note in gc.c about ambiguous case 2023-02-24 16:10:54 -05:00
Peter Zhu 3e09822407 Fix incorrect line numbers in GC hook
If the previous instruction is not a leaf instruction, then the PC was
incremented before the instruction was ran (meaning the currently
executing instruction is actually the previous instruction), so we
should not increment the PC otherwise we will calculate the source
line for the next instruction.

This bug can be reproduced in the following script:

```
require "objspace"

ObjectSpace.trace_object_allocations_start
a =

  1.0 / 0.0
p [ObjectSpace.allocation_sourceline(a), ObjectSpace.allocation_sourcefile(a)]
```

Which outputs: [4, "test.rb"]

This is incorrect because the object was allocated on line 10 and not
line 4. The behaviour is correct when we use a leaf instruction (e.g.
if we replaced `1.0 / 0.0` with `"hello"`), then the output is:
[10, "test.rb"].

[Bug #19456]
2023-02-24 14:10:09 -05:00
Takashi Kokubun 1fdaa06660 Fix a warning on typedef
../gc.c:13317:1: warning: ‘typedef’ is not at beginning of declaration [-Wold-style-declaration]
13317 | } typedef weakkeymap_entry_t;
      | ^
2023-02-23 10:13:13 -08:00
Jean Boussier 2a5354e593 Implement ObjectSpace::WeakKeyMap basic allocator
[Feature #18498]
2023-02-23 16:01:57 +01:00
git 4f48debdcf * remove trailing spaces. [ci skip] 2023-02-22 21:09:22 +00:00
Peter Zhu 29ec8e151b Make GC faster when RGENGC_CHECK_MODE >= 2
We shouldn't run gc_verify_internal_consistency after every GC step
when RGENGC_CHECK_MODE >= 2, only when GC has finished. Running it
on every GC step makes it too slow.
2023-02-22 16:09:05 -05:00
Peter Zhu 93ac7405b8 Add marking and sweeping time to GC.stat
There is a `time` key in GC.stat that gives us the total time spent in
GC. However, we don't know what proportion of the time is spent between
marking and sweeping. This makes it difficult to tune the GC as we're
not sure where to focus our efforts on.

This PR adds keys `marking_time` and `sweeping_time` to GC.stat for the
time spent marking and sweeping, in milliseconds.

[Feature #19437]
2023-02-21 08:05:31 -05:00
Peter Zhu d7c1ca48bf Refactor to separate marking and sweeping phases
This commit separates the marking and sweeping phases so that marking
functions do not directly call sweeping functions.
2023-02-21 08:05:31 -05:00
Matt Valentine-House 81dc3a1780 Remove USE_RGENGC_LOGGING_WB_UNPROTECT
This macro is broken when set to anything other than 0. And has had a
comment saying that it's broken for 3 years.

This commit deletes it and the associated logging code. It's clearly
not being used.

Co-Authored-By: Peter Zhu <peter@peterzhu.ca>
2023-02-17 09:49:45 -05:00
Nobuyoshi Nakada 21543ac86c
Fix compilation error when USE_RINCGC=0 2023-02-16 22:15:54 +09:00
Jean Boussier 1a4b4cd7f8 Move `attached_object` into `rb_classext_struct`
Given that signleton classes don't have an allocator,
we can re-use these bytes to store the attached object
in `rb_classext_struct` without making it larger.
2023-02-16 08:14:44 +01:00
Jean Boussier bac4d2eefa Check !RCLASS_EXT_EMBEDDED instead of SIZE_POOL_COUNT == 1
It's much more self documenting and consistent
2023-02-15 10:47:22 +01:00
Peter Zhu 0ddf29f4d1 Remove unused preprocessor block 2023-02-09 11:38:32 -05:00
Matt Valentine-House 72aba64fff Merge gc.h and internal/gc.h
[Feature #19425]
2023-02-09 10:32:29 -05:00
Peter Zhu 861d70e383 Rename iseq_mark_and_update to iseq_mark_and_move
The new name is more consistent.
2023-02-08 12:43:25 -05:00
Jean Boussier 3ab3455145 Add RUBY_GC_HEAP_INIT_SIZE_%d_SLOTS to pre-init pools granularly
The old RUBY_GC_HEAP_INIT_SLOTS isn't really usable anymore as
it initalize all the pools by the same factor, but it's unlikely
that pools will need similar sizes.

In production our 40B pool is 5 to 6 times bigger than our 80B pool.
2023-02-08 09:26:07 +01:00
Jean byroot Boussier 4713b084da Revert "Revert "Consider DATA objects without a mark function as protected""
This reverts commit 6eae8e5f51.
2023-02-07 22:33:12 +01:00
Jean Boussier 6eae8e5f51 Revert "Consider DATA objects without a mark function as protected"
This reverts commit 6e4c242130.
2023-02-07 15:22:06 +01:00
Jean Boussier 6e4c242130 Consider DATA objects without a mark function as protected
It's not uncommon for simple binding to wrap structs without
any Ruby object references. Hence with no `mark` function.

Might as well mark them as protected by a write barrier.
2023-02-07 11:48:49 +01:00
Peter Zhu c6f84e9189 [Bug #19398] Memory leak in WeakMap
There's a memory leak in ObjectSpace::WeakMap due to not freeing
the `struct weakmap`. It can be seen in the following script:

```
100.times do
  10000.times do
    ObjectSpace::WeakMap.new
  end

  # Output the Resident Set Size (memory usage, in KB) of the current Ruby process
  puts `ps -o rss= -p #{$$}`
end
```
2023-02-01 13:23:55 -05:00
Kunshan Wang de724487f0 Copying GC support for EXIVAR
Instance variables held in gen_ivtbl are marked with rb_gc_mark.  It
prevents the referenced objects from moving, which is bad for copying
garbage collectors.

This commit allows those instance variables to be updated during
gc_update_object_references.
2023-01-31 09:24:26 -05:00
Peter Zhu 41bf2354e3 Add rb_gc_mark_and_move and implement on iseq
This commit adds rb_gc_mark_and_move which takes a pointer to an object
and marks it during marking phase and updates references during compaction.
This allows for marking and reference updating to be combined into a
single function, which reduces code duplication and prevents bugs if
marking and reference updating goes out of sync.

This commit also implements rb_gc_mark_and_move on iseq as an example.
2023-01-19 11:23:35 -05:00
Peter Zhu abff5f6203 Move classpath to rb_classext_t
This commit moves the classpath (and tmp_classpath) from instance
variables to the rb_classext_t. This improves performance as we no
longer need to set an instance variable when assigning a classpath to
a class.

I benchmarked with the following script:

```ruby
name = :MyClass

puts(Benchmark.measure do
  10_000_000.times do |i|
    Object.const_set(name, Class.new)
    Object.send(:remove_const, name)
  end
end)
```

Before this patch:

```
  5.440119   0.025264   5.465383 (  5.467105)
```

After this patch:

```
  4.889646   0.028325   4.917971 (  4.942678)
```
2023-01-11 11:06:58 -05:00
Peter Zhu 3be2acfafd Fix re-embedding of strings during compaction
The reference updating code for strings is not re-embedding strings
because the code is incorrectly wrapped inside of a
`if (STR_SHARED_P(obj))` clause. Shared strings can't be re-embedded
so this ends up being a no-op. This means that strings can be moved to a
large size pool during compaction, but won't be re-embedded, which would
waste the space.
2023-01-09 08:49:29 -05:00
Peter Zhu 3bcf92d8af Allow malloc during gc when GC has been disabled
We should allow malloc during GC when GC has been explicitly disabled
since garbage_collect_with_gvl won't do anything if GC has been disabled.
2023-01-04 09:10:58 -05:00
Peter Zhu 184739f1e2 [ci skip] Remove trailing semicolon in gc.c 2023-01-03 11:43:43 -05:00
Peter Zhu 90a80eb076 Fix integer underflow when using HEAP_INIT_SLOTS
There is an integer underflow when the environment variable
RUBY_GC_HEAP_INIT_SLOTS is less than the number of slots currently
in the Ruby heap.

[Bug #19284]
2022-12-30 09:01:50 -05:00
Nobuyoshi Nakada 5df7118445
Skip insanely memory consuming tests
These tests do not only consume hundreds GiB bytes memory, result in
`rb_bug` when `RUBY_DEBUG` is enabled.
2022-12-26 15:01:44 +09:00
Peter Zhu 39e70eef72 [DOC] Fix formatting for GC.compact 2022-12-20 15:18:36 -05:00
Peter Zhu 9f4472cad7 [DOC] Escape all usages of GC
RDoc was making every usage of the word "GC" link to the page for GC
(which is the same page).
2022-12-20 15:16:36 -05:00
Peter Zhu 63fe03aa4e [DOC] Fix call-seq for GC methods
RDoc parses the last arrow in the call-seq as the arrow for the return
type. It was getting confused over the arrow in the hash.
2022-12-20 15:09:14 -05:00
Peter Zhu ae53986834 [DOC] Fix formatting for GC#latest_compact_info 2022-12-20 15:06:06 -05:00
Peter Zhu 80e56d1438 Fix thrashing of major GC when size pool is small
If a size pooll is small, then `min_free_slots < heap_init_slots` is true.
This means that min_free_slots will be set to heap_init_slots. This
causes `swept_slots < min_free_slots` to be true in a later if statement.
The if statement could trigger a major GC which could cause major GC
thrashing.
2022-12-20 11:32:51 -05:00
Peter Zhu e7915d6d70 Fix misfire of compaction read barrier
gc_compact_move incorrectly returns false when destination heap is full
after sweeping. It returns false even if destination heap is different
than source heap (returning false means that the source heap has
finished compacting). This causes the source page to get locked, which
causes a read barrier fire when we try to compact the source heap again.
2022-12-19 17:09:08 -05:00
Peter Zhu 8275cad1e1 Fix buffer overrun when re-embedding objects
We eagerly set the new shape of an object when moving an object during
compaction. This new shape may have a different capacity than the
current original shape capacity. This means that we cannot copy from the
original buffer using size of the new capacity. Instead, we should use
the ivar count (which is less than or equal to both the new and original
capacities).

Co-Authored-By: Matt Valentine-House <matt@eightbitraptor.com>
2022-12-19 13:13:26 -05:00
Peter Zhu 6e3bc67103 Hard crash when allocating in GC when RUBY_DEBUG
Not all builds have RGENGC_CHECK_MODE set, so it should also crash when
RUBY_DEBUG is set.
2022-12-17 09:18:54 -05:00
Peter Zhu 965f4259db Move check for GC to xmalloc and xcalloc
Moves the check earlier to before we actually perform the allocation.
2022-12-17 09:16:26 -05:00
Peter Zhu 2ccf6e5394 Don't allow allocating memory during GC
Allocating memory (xmalloc and xrealloc) during GC could cause GC to
trigger, which would crash with `[BUG] during_gc != 0`. This is an
intermittent bug which could be hard to debug.

This commit changes it so that any memory allocation during GC will
emit a warning. When debug flags are enabled it will also cause a crash.
2022-12-16 10:01:53 -05:00
Peter Zhu 5e81cf8fd0 Refactor to only attempt to move movable objects
Moves check for gc_is_moveable_obj from try_move to gc_compact_plane.

Co-Authored-By: Matt Valentine-House <matt@eightbitraptor.com>
2022-12-15 15:27:38 -05:00
Matt Valentine-House bfc66e07b7 Fix Object Movement allocation in GC
When moving Objects between size pools we have to assign a new shape.

This happened during updating references - we tried to create a new shape
tree that mirrored the existing tree, but based on the root shape of the
new size pool.

This causes allocations to happen if the new tree doesn't already exist,
potentially triggering a GC, during GC.

This commit changes object movement to look for a pre-existing new tree
during object movement, and if that tree does not exist, we don't move
the object to the new pool.

This allows us to remove the shape allocation from update references.

Co-Authored-By: Peter Zhu <peter@peterzhu.ca>
2022-12-15 15:27:38 -05:00
Jemma Issroff c1ab6ddc9a Transition complex objects to "too complex" shape
When an object becomes "too complex" (in other words it has too many
variations in the shape tree), we transition it to use a "too complex"
shape and use a hash for storing instance variables.

Without this patch, there were rare cases where shape tree growth could
"explode" and cause performance degradation on what would otherwise have
been cached fast paths.

This patch puts a limit on shape tree growth, and gracefully degrades in
the rare case where there could be a factorial growth in the shape tree.

For example:

```ruby
class NG; end

HUGE_NUMBER.times do
  NG.new.instance_variable_set(:"@unique_ivar_#{_1}", 1)
end
```

We consider objects to be "too complex" when the object's class has more
than SHAPE_MAX_VARIATIONS (currently 8) leaf nodes in the shape tree and
the object introduces a new variation (a new leaf node) associated with
that class.

For example, new variations on instances of the following class would be
considered "too complex" because those instances create more than 8
leaves in the shape tree:

```ruby
class Foo; end
9.times { Foo.new.instance_variable_set(":@uniq_#{_1}", 1) }
```

However, the following class is *not* too complex because it only has
one leaf in the shape tree:

```ruby
class Foo
  def initialize
    @a = @b = @c = @d = @e = @f = @g = @h = @i = nil
  end
end
9.times { Foo.new }
``

This case is rare, so we don't expect this change to impact performance
of most applications, but it needs to be handled.

Co-Authored-By: Aaron Patterson <tenderlove@ruby-lang.org>
2022-12-15 10:06:04 -08:00
Peter Zhu f50aa19da6 Revert "Fix Object Movement allocation in GC"
This reverts commit 9c54466e29.

We're seeing crashes in Shopify CI after this commit.
2022-12-15 12:00:30 -05:00
Matt Valentine-House 9c54466e29 Fix Object Movement allocation in GC
When moving Objects between size pools we have to assign a new shape.

This happened during updating references - we tried to create a new shape
tree that mirrored the existing tree, but based on the root shape of the
new size pool.

This causes allocations to happen if the new tree doesn't already exist,
potentially triggering a GC, during GC.

This commit changes object movement to look for a pre-existing new tree
during object movement, and if that tree does not exist, we don't move
the object to the new pool.

This allows us to remove the shape allocation from update references.

Co-Authored-By: Peter Zhu <peter@peterzhu.ca>
2022-12-15 09:04:30 -05:00
Matt Valentine-House 856e0279ec fix indentation: gc_compact_destination_pool
[ci skip]

Co-Authored-By: Peter Zhu <peter@peterzhu.ca>
2022-12-13 13:31:10 -05:00
Peter Zhu 0b4fda11ec [DOC] Don't document private methods in objspace 2022-12-12 09:48:06 -05:00
Mirek Klimos ea613c6360
Expose need_major_gc via GC.latest_gc_info (#6791) 2022-12-10 13:35:31 -05:00
Matt Valentine-House 12b5268679 Remove unused counter for heap_page->pinned_slots 2022-12-09 09:34:17 -05:00
Jemma Issroff 9c5e3671eb
Increment max_iv_count on class based on number of set_iv in initialize (#6788)
We can loosely predict the number of ivar sets on a class based on the
number of iv set instructions in the initialize method. This should give
us a more accurate estimate to use for initial size pool allocation,
which should in turn give us more cache hits.
2022-11-22 15:28:14 -05:00
Peter Zhu 5f95228c76 Add RVALUE_OVERHEAD and move ractor_belonging_id
This commit adds RVALUE_OVERHEAD for storing metadata at the end of the
slot. This commit moves the ractor_belonging_id in debug builds from the
flags to RVALUE_OVERHEAD which frees the 16 bits in the headers for
object shapes.
2022-11-21 11:26:26 -05:00
Aaron Patterson 10788166e7 Differentiate T_OBJECT shapes from other objects
We would like to differentiate types of objects via their shape.  This
commit adds a special T_OBJECT shape when we allocate an instance of
T_OBJECT.  This allows us to avoid testing whether an object is an
instance of a T_OBJECT or not, we can just check the shape.
2022-11-18 08:31:56 -08:00
S-H-GAMELINKS 1f4f6c9832 Using UNDEF_P macro 2022-11-16 18:58:33 +09:00
Jemma Issroff c726c48a3d Remove numiv from RObject
Since object shapes store the capacity of an object, we no longer
need the numiv field on RObjects. This gives us one extra slot which
we can use to give embedded objects one more instance variable (for a
total of 3 ivs). This commit removes the concept of numiv from RObject.
2022-11-10 10:11:34 -05:00
Jemma Issroff 5246f4027e Transition shape when object's capacity changes
This commit adds a `capacity` field to shapes, and adds shape
transitions whenever an object's capacity changes. Objects which are
allocated out of a bigger size pool will also make a transition from the
root shape to the shape with the correct capacity for their size pool
when they are allocated.

This commit will allow us to remove numiv from objects completely, and
will also mean we can guarantee that if two objects share shapes, their
IVs are in the same positions (an embedded and extended object cannot
share shapes). This will enable us to implement ivar sets in YJIT using
object shapes.

Co-Authored-By: Aaron Patterson <tenderlove@ruby-lang.org>
2022-11-10 10:11:34 -05:00
Yuta Saito 3a6cdeda89 [wasm] Scan machine stack based on `ec->machine.stack_{start,end}`
fiber machine stack is placed outside of C stack allocated by wasm-ld,
so highest stack address recorded by `rb_wasm_record_stack_base` is
invalid when running on non-main fiber.
Therefore, we should scan `stack_{start,end}` which always point a valid
stack range in any context.
2022-11-06 05:03:21 +09:00
Jemma Issroff 6e4b97f1da Increment max_iv_count on class in gc marking, not gc freeing
We were previously incrementing the max_iv_count on a class in gc
freeing. By the time we free an object though, we're not guaranteed its
class is still valid. Instead, we can do this when marking and we're
guaranteed the object still knows its class.
2022-11-04 11:41:10 -04:00
John Hawthorn 02f1554224
Implement object shapes for T_CLASS and T_MODULE (#6637)
* Avoid RCLASS_IV_TBL in marshal.c
* Avoid RCLASS_IV_TBL for class names
* Avoid RCLASS_IV_TBL for autoload
* Avoid RCLASS_IV_TBL for class variables
* Avoid copying RCLASS_IV_TBL onto ICLASSes
* Use object shapes for Class and Module IVs
2022-10-31 14:05:37 -07:00
Aaron Patterson 5e0432f59b
fix ASAN error in GC 2022-10-28 16:10:55 -07:00
Jemma Issroff a11952dac1 Rename `iv_count` on shapes to `next_iv_index`
`iv_count` is a misleading name because when IVs are unset, the new
shape doesn't decrement this value. `next_iv_count` is an accurate, and
more descriptive name.
2022-10-21 14:57:34 -07:00
Jemma Issroff 13bd617ea6 Remove unused class serial
Before object shapes, we were using class serial to invalidate
inline caches. Now that we use shape_id for inline cache keys,
the class serial is unnecessary.

Co-Authored-By: Aaron Patterson <tenderlove@ruby-lang.org>
2022-10-21 14:56:48 -07:00
Nobuyoshi Nakada e72c5044ce
Check writebarrier arguments only when RGENGC_CHECK_MODE [ci skip]
The commit 575ae50d16a03ed23357ec4ea0dbf7167fc26c8c was for debugging
the failure triggered by f55212bce9, and
it was fixed at the commit 39f7eddec4.
2022-10-21 10:02:16 +09:00
Nobuyoshi Nakada 9a0a165a5d Check writebarrier arguments 2022-10-20 15:43:34 -04:00
Aaron Patterson eeea633eb2 Stop zeroing memory on allocation / copy
Shapes gives us an almost exact count of instance variables on an
object.  Since we know the number of instance variables that have been
set, we will never access slots that haven't been initialized with an
IV.
2022-10-19 07:54:46 -07:00
Sergey Fedorov 567725ed30
Fix and improve coroutines for Darwin (macOS) ppc/ppc64. (#5975) 2022-10-19 23:49:45 +13:00
Aaron Patterson f0654b1027 More precisely iterate over Object instance variables
Shapes provides us with an (almost) exact count of instance variables.
We only need to check for Qundef when an IV has been "undefined"
Prefer to use ROBJECT_IV_COUNT when iterating IVs
2022-10-15 10:44:10 -07:00
Nobuyoshi Nakada 5ccb625fbb
Use `roomof` macro for rounding up divisions 2022-10-14 19:23:25 +09:00
Jemma Issroff ad63b668e2
Revert "Revert "This commit implements the Object Shapes technique in CRuby.""
This reverts commit 9a6803c90b.
2022-10-11 08:40:56 -07:00
Samuel Williams e4f91bbdba
Add IO#timeout attribute and use it for blocking IO operations. (#5653) 2022-10-07 21:48:38 +13:00
Nobuyoshi Nakada 40ceceb1a5 [Bug #19028] Suppress GCC 12 `-Wuse-after-free` false warning
GCC 12 introduced a new warning flag `-Wuse-after-free`, however it
has a false positive at `realloc` when optimization is disabled, since
the memory requested for reallocation is guaranteed to not be touched.
This workaround is very unclear why the false warning is suppressed by
a statement-expression GCC extension.
2022-10-04 21:53:59 +09:00
Aaron Patterson 9a6803c90b
Revert "This commit implements the Object Shapes technique in CRuby."
This reverts commit 68bc9e2e97d12f80df0d113e284864e225f771c2.
2022-09-30 16:01:50 -07:00
Jemma Issroff d594a5a8bd
This commit implements the Object Shapes technique in CRuby.
Object Shapes is used for accessing instance variables and representing the
"frozenness" of objects.  Object instances have a "shape" and the shape
represents some attributes of the object (currently which instance variables are
set and the "frozenness").  Shapes form a tree data structure, and when a new
instance variable is set on an object, that object "transitions" to a new shape
in the shape tree.  Each shape has an ID that is used for caching. The shape
structure is independent of class, so objects of different types can have the
same shape.

For example:

```ruby
class Foo
  def initialize
    # Starts with shape id 0
    @a = 1 # transitions to shape id 1
    @b = 1 # transitions to shape id 2
  end
end

class Bar
  def initialize
    # Starts with shape id 0
    @a = 1 # transitions to shape id 1
    @b = 1 # transitions to shape id 2
  end
end

foo = Foo.new # `foo` has shape id 2
bar = Bar.new # `bar` has shape id 2
```

Both `foo` and `bar` instances have the same shape because they both set
instance variables of the same name in the same order.

This technique can help to improve inline cache hits as well as generate more
efficient machine code in JIT compilers.

This commit also adds some methods for debugging shapes on objects.  See
`RubyVM::Shape` for more details.

For more context on Object Shapes, see [Feature: #18776]

Co-Authored-By: Aaron Patterson <tenderlove@ruby-lang.org>
Co-Authored-By: Eileen M. Uchitelle <eileencodes@gmail.com>
Co-Authored-By: John Hawthorn <john@hawthorn.email>
2022-09-28 08:26:21 -07:00
Nobuyoshi Nakada a05b261464 Always use the longer version of `TRY_WITH_GC` 2022-09-28 23:51:38 +09:00
Aaron Patterson 06abfa5be6
Revert this until we can figure out WB issues or remove shapes from GC
Revert "* expand tabs. [ci skip]"

This reverts commit 830b5b5c35.

Revert "This commit implements the Object Shapes technique in CRuby."

This reverts commit 9ddfd2ca00.
2022-09-26 16:10:11 -07:00
git 830b5b5c35 * expand tabs. [ci skip]
Tabs were expanded because the file did not have any tab indentation in unedited lines.
Please update your editor config, and use misc/expand_tabs.rb in the pre-commit hook.
2022-09-27 01:21:58 +09:00
Jemma Issroff 9ddfd2ca00 This commit implements the Object Shapes technique in CRuby.
Object Shapes is used for accessing instance variables and representing the
"frozenness" of objects.  Object instances have a "shape" and the shape
represents some attributes of the object (currently which instance variables are
set and the "frozenness").  Shapes form a tree data structure, and when a new
instance variable is set on an object, that object "transitions" to a new shape
in the shape tree.  Each shape has an ID that is used for caching. The shape
structure is independent of class, so objects of different types can have the
same shape.

For example:

```ruby
class Foo
  def initialize
    # Starts with shape id 0
    @a = 1 # transitions to shape id 1
    @b = 1 # transitions to shape id 2
  end
end

class Bar
  def initialize
    # Starts with shape id 0
    @a = 1 # transitions to shape id 1
    @b = 1 # transitions to shape id 2
  end
end

foo = Foo.new # `foo` has shape id 2
bar = Bar.new # `bar` has shape id 2
```

Both `foo` and `bar` instances have the same shape because they both set
instance variables of the same name in the same order.

This technique can help to improve inline cache hits as well as generate more
efficient machine code in JIT compilers.

This commit also adds some methods for debugging shapes on objects.  See
`RubyVM::Shape` for more details.

For more context on Object Shapes, see [Feature: #18776]

Co-Authored-By: Aaron Patterson <tenderlove@ruby-lang.org>
Co-Authored-By: Eileen M. Uchitelle <eileencodes@gmail.com>
Co-Authored-By: John Hawthorn <john@hawthorn.email>
2022-09-26 09:21:30 -07:00
Samuel Williams 22af2e9084 Rework vm_core to use `int first_lineno` struct member. 2022-09-26 00:41:16 +13:00
Nobuyoshi Nakada ff07e5c264
Skip poisoned regions
Poisoned regions cannot be accessed without unpoisoning outside gc.c.
Specifically, debug.gem is terminated by AddressSanitizer.

```
SUMMARY: AddressSanitizer: use-after-poison iseq_collector.c:39 in iseq_i
```
2022-08-09 20:11:48 +09:00
Peter Zhu 229cf263df Lock the VM for rb_gc_writebarrier_unprotect
When using Ractors, rb_gc_writebarrier_unprotect requries a VM lock
since it modifies the bitmaps.
2022-07-28 10:02:12 -04:00
Peter Zhu 1c16645216 Make array slices views rather than copies
Before this commit, if the slice fits in VWA, it would make a copy
rather than a view. This is slower as it requires a memcpy of the
contents.
2022-07-28 10:02:12 -04:00
Peter Zhu 2375afb8d6 Refactor gc_ref_update_array 2022-07-28 10:02:12 -04:00
Nobuyoshi Nakada 5d5c1d0fbd
Suppress use-after-free warning by gcc-12 2022-07-28 09:06:42 +09:00
Nobuyoshi Nakada f42230ff22
Adjust styles [ci skip] 2022-07-27 18:42:27 +09:00
git 3b1ed03d8c * expand tabs. [ci skip]
Tabs were expanded because the file did not have any tab indentation in unedited lines.
Please update your editor config, and use misc/expand_tabs.rb in the pre-commit hook.
2022-07-27 01:40:03 +09:00
Jemma Issroff 36d0c71ace
Refactored poisoning and unpoisoning freelist to simpler API 2022-07-26 09:39:31 -07:00
Peter Zhu efb91ff19b Rename rb_ary_tmp_new to rb_ary_hidden_new
rb_ary_tmp_new suggests that the array is temporary in some way, but
that's not true, it just creates an array that's hidden and not on the
transient heap. This commit renames it to rb_ary_hidden_new.
2022-07-26 09:12:09 -04:00
Nobuyoshi Nakada b30b727c24
Fix format specifier
`uintptr_t` is not always `unsigned long`, but can be casted to void
pointer safely.
2022-07-25 09:18:36 +09:00
Takashi Kokubun 5b21e94beb Expand tabs [ci skip]
[Misc #18891]
2022-07-21 09:42:04 -07:00
Peter Zhu cdbb9b8555 [Bug #18929] Fix heap creation thrashing in GC
Before this commit, if we don't have enough slots after sweeping but
had pages on the tomb heap, then the GC would frequently allocate and
deallocate pages. This is because after sweeping it would set
allocatable pages (since there were not enough slots) but free the
pages on the tomb heap.

This commit reuses pages on the tomb heap if there's not enough slots
after sweeping.
2022-07-21 10:46:32 -04:00
Peter Zhu 1c9acb6bb1 Refactor macros of array.c
Move some macros in array.c to internal/array.h so that other files
can also access these macros.
2022-07-21 09:02:45 -04:00
Daniel Colson 32e406d6d3 Ensure _id2ref finds symbols with the correct type
Prior to this commit it was possible to call `ObjectSpace._id2ref` with
an offset static symbol object_id and get back a new, incorrectly tagged
symbol:

```
> sensible_sym = ObjectSpace._id2ref(:a.object_id)
=> :a
> nonsense_sym = ObjectSpace._id2ref(:a.object_id + 40)
=> :a
> sensible_sym == nonsense_sym
=> false
```

`nonsense_sym` ends up tagged with `RUBY_ID_INSTANCE` instead of
`RB_ID_LOCAL`. That means we can do silly things like:

```
> foo = Object.new
> foo.instance_variable_set(:a, 123)
(irb):2:in `instance_variable_set': `a' is not allowed as an instance variable name (NameError)
> foo.instance_variable_set(ObjectSpace._id2ref(:a.object_id + 40), 123)
=> 123
> foo.instance_variables
=> [:a]
```

This was happening because `get_id_entry` ignores the tag bits when
looking up the symbol. So `rb_id2str(symid)` would return a value and
then we'd continue on with the nonsense `symid`.

This commit prevents the situation by checking that the `symid` actually
matches what we get back from `get_id_entry`. Now we get a `RangeError`
for the nonsense id:

```
> ObjectSpace._id2ref(:a.object_id)
=> :a
> ObjectSpace._id2ref(:a.object_id + 40)
(irb):1:in `_id2ref': 0x000000000013f408 is not symbol id value (RangeError)
```

Co-authored-by: John Hawthorn <jhawthorn@github.com>
2022-07-20 10:38:44 -07:00
Peter Zhu 86d061294d [Bug #18928] Fix crash in WeakMap
In wmap_live_p, if is_pointer_to_heap returns false, then the page is
either in the tomb or has already been freed, so the object is dead. In
this case, wmap_live_p should return false.
2022-07-20 08:40:31 -04:00
Nobuyoshi Nakada 472740de41
Fix free objects count condition
Free objects have `T_NONE` as the builtin type.  A pointer to a valid
array element will never be `NULL`.
2022-07-20 17:39:54 +09:00
Peter Zhu 7424ea184f Implement Objects on VWA
This commit implements Objects on Variable Width Allocation. This allows
Objects with more ivars to be embedded (i.e. contents directly follow the
object header) which improves performance through better cache locality.
2022-07-15 09:21:07 -04:00
Matt Valentine-House 214ed4cbc6 [Feature #18901] Support size pool movement for Arrays
This commit enables Arrays to move between size pools during compaction.
This can occur if the array is mutated such that it would fit in a
different size pool when embedded.

The move is carried out in two stages:

1. The RVALUE is moved to a destination heap during object movement
   phase of compaction
2. The array data is re-embedded and the original buffer free'd if
   required. This happens during the update references step
2022-07-12 08:50:33 -04:00
Matt Valentine-House a6dd859aff Add expand_heap option to GC.verify_compaction_references
In order to reliably test compaction we need to be able to move objects
between size pools.

In order for this to happen there must be pages in a size pool into
which we can allocate.

The existing implementation of `double_heap` only doubled the existing
number of pages in the heap, so if a size pool had a low number of pages
(or 0) it's not guaranteed that enough space will be created to move
objects into that size pool.

This commit deprecates the `double_heap` option and replaces it with
`expand_heap` instead.

expand heap will expand each heap by enough pages to hold a number of
slots defined by `GC_HEAP_INIT_SLOTS` or by `heap->total_pags` whichever
is larger.

If both `double_heap` and `expand_heap` are present, a deprecation
warning will be shown for `double_heap` and the `expand_heap` behaviour
will take precedence

Given that this is an API intended for debugging and testing GC
compaction I'm not concerned about the extra memory usage or time taken
to create the pages. However, for completeness:

Running the following `test.rb` and using `time` on my Macbook Pro shows
the following memory usage and time impact:

pp "RSS (kb): #{`ps -o rss #{Process.pid}`.lines.last.to_i}"
GC.verify_compaction_references(double_heap: true, toward: :empty)
pp "RSS (kb): #{`ps -o rss #{Process.pid}`.lines.last.to_i}"

❯ time make run
./miniruby -I./lib -I. -I.ext/common  -r./arm64-darwin21-fake  ./test.rb
"RSS (kb): 24000"
<internal:gc>:251: warning: double_heap is deprecated and will be removed
"RSS (kb): 25232"

________________________________________________________
Executed in  124.37 millis    fish           external
   usr time   82.22 millis    0.09 millis   82.12 millis
   sys time   28.76 millis    2.61 millis   26.15 millis

❯ time make run
./miniruby -I./lib -I. -I.ext/common  -r./arm64-darwin21-fake  ./test.rb
"RSS (kb): 24000"
"RSS (kb): 49040"

________________________________________________________
Executed in  150.13 millis    fish           external
   usr time  103.32 millis    0.10 millis  103.22 millis
   sys time   35.73 millis    2.59 millis   33.14 millis
2022-07-11 09:00:03 -04:00
Nobuyoshi Nakada ec09ba58d1
Extract `atomic_inc_wraparound` function 2022-07-10 17:56:36 +09:00
Nobuyoshi Nakada b1b8172328
Add `asan_unpoisoning_object` to execute the block with unpoisoning 2022-07-10 13:11:07 +09:00
Nobuyoshi Nakada ec303e49af
Split `rb_raw_obj_info` 2022-07-10 13:11:07 +09:00
Nobuyoshi Nakada 233054a609
Cycle `obj_info_buffers_index` atomically 2022-07-10 13:11:06 +09:00
Nobuyoshi Nakada a006dcb73f
`APPEND_S` for no conversion formats 2022-07-10 13:07:40 +09:00
Nobuyoshi Nakada 2bf0313561
Rewrite `APPENDF` using variadic arguments 2022-07-10 13:03:22 +09:00
Nobuyoshi Nakada 51025a9013
Use `size_t` for `rb_raw_obj_info` 2022-07-10 13:03:22 +09:00
Nobuyoshi Nakada fbe3651466
Use `asan_unpoison_object_temporary` 2022-07-10 13:03:22 +09:00
Nobuyoshi Nakada b16f44ad4f
Get rid of static buffer in `obj_info` 2022-07-10 13:03:21 +09:00
Nobuyoshi Nakada 61c7ae4d27 Gather heap page size conditions combination
When similar combination of conditions are separated in two places, it
is harder to make sure the conditional blocks match each other,
2022-07-07 22:39:59 +09:00
Peter Zhu f36859869f Improve error message for segv in read_barrier_handler
If the page_body is a null pointer, then read_barrier_handler will
crash with an unrelated message. This commit improves the error message.

Before:

test.rb:1: [BUG] Couldn't unprotect page 0x0000000000000000, errno: Cannot allocate memory

After:

test.rb:1: [BUG] read_barrier_handler: segmentation fault at 0x14
2022-07-07 09:39:28 -04:00
Peter Zhu d6c98626da Fix crash in compaction due to unlocked page
The page of src could be partially compacted, so it may contain
T_MOVED. Sweeping a page may read objects on this page, so we
need to lock the page.
2022-07-07 09:39:28 -04:00
Peter Zhu d7c5a6d49b Fix typo in gc_compact_move
The page we're sweeping is on the destination heap `dheap`, not the
source heap `heap`.
2022-07-07 09:39:28 -04:00
Nobuyoshi Nakada f681f9ae24
Adjust indents [ci skip] 2022-07-06 00:45:06 +09:00
Nobuyoshi Nakada cab10a2c50
Extract `protect_page_body` to fix mismatched braces 2022-06-18 10:20:46 +09:00
KJ Tsanaktsidis 05ffc037ad Disable Mach exception handlers when read barriers in place
The GC compaction mechanism implements a kind of read barrier by marking
some (OS) pages as unreadable, and installing a SIGBUS/SIGSEGV handler
to detect when they're accessed and invalidate an attempt to move the
object.

Unfortunately, when a debugger is attached to the Ruby interpreter on
Mac OS, the debugger will trap the EXC_BAD_ACCES mach exception before
the runtime can transform that into a SIGBUS signal and dispatch it.
Thus, execution gets stuck; any attempt to continue from the debugger
re-executes the line that caused the exception and no forward progress
can be made.

This makes it impossible to debug either the Ruby interpreter or a C
extension whilst compaction is in use.

To fix this, we disable the EXC_BAD_ACCESS handler when installing the
SIGBUS/SIGSEGV handlers, and re-enable them once the compaction is done.
The debugger will still trap on the attempt to read the bad page, but it
will be trapping the SIGBUS signal, rather than the EXC_BAD_ACCESS mach
exception. It's possible to continue from this in the debugger, which
invokes the signal handler and allows forward progress to be made.
2022-06-18 00:10:16 +09:00
Nobuyoshi Nakada 2c19086323
Suppress code unused unless GC_CAN_COMPILE_COMPACTION 2022-06-17 10:47:16 +09:00
Peter Zhu 79eaaf2d0b Include runtime checks for compaction support
Commit 0c36ba5319 changed GC compaction
methods to not be implemented when not supported. However, that commit
only does compile time checks (which currently only checks for WASM),
but there are additional compaction support checks during run time.

This commit changes it so that GC compaction methods aren't defined
during run time if the platform does not support GC compaction.

[Bug #18829]
2022-06-16 10:18:46 -04:00
Peter Zhu 52d42e7023 Rename GC_COMPACTION_SUPPORTED
Naming this macro GC_COMPACTION_SUPPORTED is misleading because it
only checks whether compaction is supported at compile time.

[Bug #18829]
2022-06-16 10:18:46 -04:00
Takashi Kokubun 1162523bae
Remove MJIT worker thread (#6006)
[Misc #18830]
2022-06-15 09:40:54 -07:00
Matt Valentine-House 56cc3e99b6 Move String RVALUES between pools
And re-embed any strings that can now fit inside the slot they've been
moved to
2022-06-13 10:11:27 -07:00
Peter Zhu 8d57336360 Fix major GC thrashing
Only growth heaps are allowed to start major GCs. Before this patch,
growth heaps are defined as size pools that freed more slots than had
empty slots (i.e. there were more dead objects that empty space).

But if the size pool is relatively stable and tightly packed with mostly
old objects and has allocatable pages, then it would be incorrectly
classified as a growth heap and trigger major GC. But since it's stable,
it would not use any of the allocatable pages and forever be classified
as a growth heap, causing major GC thrashing. This commit changes the
definition of growth heap to require that the size pool to have no
allocatable pages.
2022-06-08 12:09:19 -04:00
Peter Zhu d1b6c8a1cc Fix compilation error when USE_RVARGC=0
force_major_gc_count was not defined when USE_RVARGC=0.
2022-06-08 11:25:31 -04:00
Peter Zhu fafe68185c Add key force_major_gc_count to GC.stat_heap
force_major_gc_count is the number of times the size pool forced major
GC to run.
2022-06-08 10:03:00 -04:00
Peter Zhu c4bf24ee46 Remove while loop over heap_prepare
Having a while loop over `heap_prepare` makes the GC logic difficult to
understand (it is difficult to understand when and why `heap_prepare`
yields a free page). It is also a source of bugs and can cause an infinite
loop if `heap_page` never yields a free page.
2022-06-07 09:56:20 -04:00
Nobuyoshi Nakada af90433876
Typedef built-in function types 2022-06-02 16:05:35 +09:00
Nobuyoshi Nakada b96a3a6fd2
Move `GC.verify_compaction_references` [Bug #18779]
Define `GC.verify_compaction_references` as a built-in ruby method,
according to GC compaction support via `GC::OPTS`.
2022-06-02 15:32:00 +09:00
Nobuyoshi Nakada dfc8060756
Adjust indent and nesting [ci skip] 2022-06-02 14:34:48 +09:00
Mike Dalessio 0c36ba5319 Define unsupported GC compaction methods as rb_f_notimplement
Fixes [Bug #18779]

Define the following methods as `rb_f_notimplement` on unsupported
platforms:

- GC.compact
- GC.auto_compact
- GC.auto_compact=
- GC.latest_compact_info
- GC.verify_compaction_references

This change allows users to call `GC.respond_to?(:compact)` to
properly test for compaction support. Previously, it was necessary to
invoke `GC.compact` or `GC.verify_compaction_references` and check if
those methods raised `NotImplementedError` to determine if compaction
was supported.

This follows the precedent set for other platform-specific
methods. For example, in `process.c` for methods such as
`Process.fork`, `Process.setpgid`, and `Process.getpriority`.
2022-05-24 09:40:03 -07:00
Mike Dalessio 0de1495f35 Move compaction-related methods into gc.c
These methods are removed from gc.rb and added to gc.c:

- GC.compact
- GC.auto_compact
- GC.auto_compact=
- GC.latest_compact_info
- GC.verify_compaction_references

This is a prefactor to allow setting these methods to
`rb_f_notimplement` in a followup commit.
2022-05-24 09:40:03 -07:00
Matt Valentine-House 708e839dee Fix compiler warning when USE_RVARGC=0 2022-05-13 16:26:41 -04:00
Kaíque Kandy Koga a85cdb5a6e
Write have instead of have have [ci skip 2022-05-10 13:07:16 +09:00
Peter Zhu 85479b34f7 Don't allocate new page on finish sweeping
We don't need to allocate a new page in gc_sweep_finish_size_pool.
It can be allocated when needed.
2022-05-09 08:45:24 -04:00
Peter Zhu e28e9c63c6 Fix heap_extend_pages when total_slots is 0
Some size pools may not have any pages/slots, so total_slots is 0. This
causes a divide-by-zero in the calculation. This commit adds a special
case to catch the case when total_slots is 0 and returns the number of
pages for heap_init_slots.
2022-05-09 08:45:24 -04:00
Peter Zhu f7d480378a Grow size pools with no or few slots
If the size pool has no or few pages/slots, then min_free_slots will
be a very small number (or even 0). Then the heap won't be eligible to
grow, causing GC thrashing or infinite loops.
2022-05-09 08:45:24 -04:00
Peter Zhu b3f3cb0c38 Call gc_sweep_finish_size_pool on size pools with no pages
Size pools with no pages won't be swept so gc_sweep_finish_size_pool
will never be called on it, but gc_sweep_finish_size_pool must be called
to grow the size pool.
2022-05-09 08:45:24 -04:00
Peter Zhu 033e58cf2c Fix gc_page_sweep when last bitmap plane is not used
Depending on alignment, the last bitmap plane may not used. Then it will
appear as if all of the objects on that plane is unmarked, which will
cause a buffer overrun when we try to free the object. This commit
changes the loop to calculate the number of planes used
(bitmap_plane_count).
2022-05-09 08:45:24 -04:00
Alan Wu cae85c528c Mark RCLASS_INCLUDER
Since 4d8f76286b, we need to dereference
the includer field on iclasses, so we need to mark it to make sure
it's alive.

Sometimes during compaction we crash because the field is dangling,
though I have a hard time constructing such a situation. See
http://ci.rvm.jp/results/trunk@ruby-iga/3947725
2022-05-05 17:37:07 -04:00
Jemma Issroff d7df8c6964 Unpoison freelist when iterating over it in gc_sweep_page 2022-05-04 12:49:15 -07:00
Peter Zhu bff31b3208 Remove unneeded cast
`start` is of type uintptr_t so it does not need to be casted to VALUE.
2022-05-04 09:24:03 -04:00
Alan Wu 379f5a6e8e Update reference for RCLASS_INCLUDER during compaction
We didn't update the includer field during compaction so it could become
a dangling pointer after compaction. It's only recently that we started
to dereference the field, and we were only comparing the pointer before
then, so the omission only recently started to cause crashes.

By instrumenting object.c:833 with `rp(includer);`, you can see the
includer field become `T_NONE` with the following script:

```ruby
mod = Module.new do
  protected def foo = 1
end

klass = Class.new do
  include Module.new
  def run
    foo
  end
end

klass.include(mod)

GC.verify_compaction_references(double_heap: true, toward: :empty)

klass.new.run
```

I found a crash in a private application that this patch fixes, but
wasn't able to develop a small reproducer. Hence the above demo that
requires instrumentation.
2022-05-03 16:48:46 -04:00
Nobuyoshi Nakada df1594e4b5
Parenthize macro arguments 2022-04-13 22:55:20 +09:00
Kazuhiro NISHIYAMA 48ffa28044
Fix a typo [ci skip] 2022-04-12 19:14:39 +09:00
S-H-GAMELINKS 5b467400d2 [DOC]Some link prefix replace 2022-04-09 17:43:46 +09:00
Nobuyoshi Nakada 5af507f527
Update `heap_pages_deferred_final` atomically 2022-04-07 12:19:18 +09:00
Eric Wong a19b2d59fc ruby_gc_set_params: update malloc_limit when env is set
During VM startup, rb_objspace_alloc sets malloc_limit
(objspace->malloc_params.limit) before ruby_gc_set_params is called, thus
nullifying the effect of RUBY_GC_MALLOC_LIMIT before the initial GC run.

The call sequence is as follows:

  main.c::main()
    ruby_init
      ruby_setup
        Init_BareVM
          rb_objspace_alloc // malloc_limit = gc_params.malloc_limit_min;
    ruby_options
      ruby_process_options
        process_options
          ruby_gc_set_params // RUBY_GC_MALLOC_LIMIT => gc_params.malloc_limit_min

With ruby_gc_set_params setting malloc_limit, RUBY_GC_MALLOC_LIMIT
affects the process sooner.

[ruby-core:107170]
2022-04-04 21:46:02 +00:00
Peter Zhu ea9c09a92c Disable mmap on WASM
WASM does not have proper support for mmap.
2022-04-04 09:27:14 -04:00
Peter Zhu c482ee4025 Make heap page sizes 64KiB by default
Commit dde164e968 decoupled incremental
marking from page sizes. This commit changes Ruby heap page sizes to
64KiB. Doing so will have several benefits:

1. We can use compaction on systems with 64KiB system page sizes (e.g.
   PowerPC).
2. Larger page sizes will allow Variable Width Allocation to increase
   slot sizes and embed larger objects.
3. Since commit 002fa28599, macOS has 64
   KiB pages. Making page sizes 64 KiB will bring these systems to
   parity.

I have attached some bechmark results below.

Discourse:
    On Discourse, we saw much better p99 performance (e.g. for "categories"
    it went from 214ms on master to 134ms on branch, for "home" it went
    from 265ms to 251ms). We don’t see much change in p60, p75, and p90
    performance. We also see a slight decrease in memory usage by 1.04x.

    Branch RSS: 354.9MB
    Master RSS: 368.2MB

railsbench:
    On rails bench, we don’t see a big change in RPS or p99
    performance. We don’t see a big difference in memory usage.

    Branch RPS: 826.27
    Master RPS: 824.85

    Branch p99: 1.67
    Master p99: 1.72

    Branch RSS: 88.72MB
    Master RSS: 88.48MB

liquid:
    We don’t see a significant change in liquid performance.

    Branch parse & render: 28.653 I/s
    Master parse & render: 28.563 i/s
2022-04-04 09:27:14 -04:00
Matt Valentine-House 651b832c1b extract magic number from gc_sweep_step 2022-04-01 10:52:18 -04:00
Peter Zhu fe21b7794a Use mmap for heap page allocation only
Currently, rb_aligned_malloc uses mmap if Ruby heap pages can be
allocated through mmap (when system heap page size <= Ruby heap page
size). If Ruby heap page sizes is increased to 64KiB, then mmap will
be used on systems with 64KiB system page sizes. However, the transient
heap also uses rb_aligned_malloc and requires 32KiB alignment. This
would break in the current implementation since it would allocate sizes
through mmap that is not a multiple of the system page size.

This commit adds heap_page_body_allocate which will use mmap when
possible and changes rb_aligned_malloc to not use mmap (and only
use posix_memalign).
2022-04-01 10:27:18 -04:00
Matt Valentine-House d8352ff3ac [Feature #18619] remove FL_FROM_FREELIST 2022-04-01 08:45:52 -04:00