Commit graph

2609 commits

Author SHA1 Message Date
Peter Zhu
08731182b8 Change is_garbage_object to return a bool 2024-02-27 14:52:02 -05:00
Peter Zhu
3c44f6da6c Simplify is_garbage_object 2024-02-27 14:52:02 -05:00
Peter Zhu
1f740cd111 Remove is_swept_object
The name is misleading, as it seems like the function checks whether the
object is swept or not. But the function only checks whether the page is
before or after sweeping.
2024-02-27 12:10:48 -05:00
Peter Zhu
2396b7a62f Change is_live_object to return a bool 2024-02-27 10:03:42 -05:00
Peter Zhu
9ba53cb688 Simplify is_live_object 2024-02-27 10:03:42 -05:00
Peter Zhu
78ae6dbb11 Remove rb_objspace_marked_object_p
rb_objspace_marked_object_p is no longer used in the objspace module, so
we can remove it.
2024-02-26 17:05:34 -05:00
Peter Zhu
7538703d1b Make rb_objspace_data_type_memsize private
rb_objspace_data_type_memsize is not used in the objspace module, so we
can make it private.
2024-02-26 17:05:34 -05:00
Peter Zhu
c9b6cd4223 Remove unused rb_objspace_each_objects_without_setup 2024-02-26 14:34:24 -05:00
Peter Zhu
27e3e44390 Fix verify_internal_consistency_i for zombie objects
FL_FINALIZE is now kept for zombie objects.
2024-02-26 11:38:44 -05:00
Peter Zhu
83e676e5f9 Don't lookup finalizers if FL_FINALIZE flag not set
The FL_FINALIZE flag is set when there are finalizers for the object. We
can improver performance by not looking up in the table if the flag is
not set.

Using the following C extension:

    #include "ruby/ruby.h"

    static void data_free(void *_ptr) {}

    static const rb_data_type_t data_type = {
        "my_type",
        {
            NULL,
            data_free,
        },
        0, 0, 0
    };

    static VALUE data_alloc(VALUE klass) {
        return TypedData_Wrap_Struct(klass, &data_type, (void *)1);
    }

    void Init_myext(void) {
        VALUE my_klass = rb_define_class("MyClass", rb_cObject);
        rb_define_alloc_func(my_klass, data_alloc);
    }

And the following benchmark:

    require "benchmark"

    final_objs = 1_000_000.times.map do
      o = Object.new
      ObjectSpace.define_finalizer(o, proc {})
      o
    end

    puts(Benchmark.measure do
      100_000_000.times do
        MyClass.new
      end
    end)

Before:

    10.974190   0.355037  11.329227 ( 11.416772)

After:

    7.664310   0.347598   8.011908 (  8.268969)
2024-02-26 09:20:05 -05:00
Peter Zhu
e65315a725 Extract imemo functions from gc.c into imemo.c 2024-02-22 11:35:09 -05:00
Peter Zhu
330830dd1a Add IMEMO_NEW
Rather than exposing that an imemo has a flag and four fields, this
changes the implementation to only expose one field (the klass) and
fills the rest with 0. The type will have to fill in the values themselves.
2024-02-21 11:33:05 -05:00
Peter Zhu
402690c3b6 Fix incomplete switch statement in imemo_memsize
The switch statement is not exhaustive, meaning the "unreachable"
comment was not correct. This commit fixes it by making the list
exhaustive and adding an rb_bug in the default case.
2024-02-21 10:13:36 -05:00
John Hawthorn
1c97abaaba De-dup identical callinfo objects
Previously every call to vm_ci_new (when the CI was not packable) would
result in a different callinfo being returned this meant that every
kwarg callsite had its own CI.

When calling, different CIs result in different CCs. These CIs and CCs
both end up persisted on the T_CLASS inside cc_tbl. So in an eval loop
this resulted in a memory leak of both types of object. This also likely
resulted in extra memory used, and extra time searching, in non-eval
cases.

For simplicity in this commit I always allocate a CI object inside
rb_vm_ci_lookup, but ideally we would lazily allocate it only when
needed. I hope to do that as a follow up in the future.
2024-02-20 18:55:00 -08:00
Peter Zhu
97d4363d3b [DOC] Improve docs for GC.latest_compact_info 2024-02-20 17:39:46 -05:00
Peter Zhu
c184aa8740 Use rb_gc_mark_and_move for imemo 2024-02-20 10:39:30 -05:00
Peter Zhu
24645cff0d Removed duplicated variable in push_mark_stack 2024-02-16 13:27:16 -05:00
Peter Zhu
4411cdeef9 Fix typo in gc.c 2024-02-16 11:44:27 -05:00
Peter Zhu
28709d591d Remove unused argument in cc_table_free 2024-02-14 16:25:05 -05:00
Peter Zhu
ae8db4b65a Remove unused function rb_cc_table_free 2024-02-14 15:52:15 -05:00
Peter Zhu
1d3b306753 Move rb_class_allocate_instance from gc.c to object.c 2024-02-14 13:43:02 -05:00
Alan Wu
5add999dee Comment about not marking RSYMBOL(obj)->fstr [ci skip] 2024-02-13 14:49:54 -05:00
Peter Zhu
190a55d27f Drill newobj cache instead of ractor 2024-02-12 09:43:38 -05:00
Peter Zhu
a50e35888b Free all remaining objects in rb_objspace_free_objects
rb_objspace_call_finalizer didn't free fibers and neither did
rb_objspace_free_objects, which caused fibers to be reported as leaked
when using RUBY_FREE_AT_EXIT. This commit changes rb_objspace_free_objects
to free all remaining Ruby objects.
2024-02-06 10:54:05 -05:00
KJ Tsanaktsidis
4f4f3a6dec Don't check __asan_region_is_poisoned in objspace_each_objects
This returns whether or not _any_ piece of memory in the range is
poisoned, not if _all_ of it is. That means that currently, with ASAN
enabled, pages which contain a single poisoned object are skipped
entirely from being iterated with objspace_each* family of functions.

[Bug #20220]
2024-02-06 22:23:42 +11:00
Peter Zhu
d0b774cfb8 Remove null checks for xfree
xfree can handle null values, so we don't need to check it.
2024-01-19 10:25:02 -05:00
KJ Tsanaktsidis
61da90c1b8 Mark asan fake stacks during machine stack marking
ASAN leaves a pointer to the fake frame on the stack; we can use the
__asan_addr_is_in_fake_stack API to work out the extent of the fake
stack and thus mark any VALUEs contained therein.

[Bug #20001]
2024-01-19 09:55:12 +11:00
Peter Zhu
cc7b19e048 [DOC] Improve docs for GC.compact 2024-01-15 11:27:31 -05:00
Alan Wu
e59dd7094f Pass more T_DATA to obj_free() under RUBY_FREE_AT_EXIT
T_DATA without a pointer or free function may still have ivars set on
them that need to be freed. The following leaked generic ivars for
example:

    converter = Encoding::Converter.allocate
    converter.instance_variable_set(:@foo, 1)

    STACK OF 1 INSTANCE OF 'ROOT LEAK: <malloc in objspace_xmalloc0>':
    <snip>
    12  miniruby    0x10286ec50 ivar_set + 140  variable.c:1850
    11  miniruby    0x102876afc generic_ivar_set + 136  variable.c:1668
2024-01-12 13:28:36 -05:00
KJ Tsanaktsidis
ac0ba3c07e Revert "Allow each_stack_location to accept context for the callback"
This reverts commit 179228cd83.
2024-01-12 17:58:54 +11:00
KJ Tsanaktsidis
688a6ff510 Revert "Mark asan fake stacks during machine stack marking"
This reverts commit d10bc3a2b8.
2024-01-12 17:58:54 +11:00
KJ Tsanaktsidis
d10bc3a2b8 Mark asan fake stacks during machine stack marking
ASAN leaves a pointer to the fake frame on the stack; we can use the
__asan_addr_is_in_fake_stack API to work out the extent of the fake
stack and thus mark any VALUEs contained therein.

[Bug #20001]
2024-01-12 17:29:48 +11:00
KJ Tsanaktsidis
179228cd83 Allow each_stack_location to accept context for the callback
This is preparing for a more specialised, asan-aware version of
gc_mark_maybe which needs some additional context passed through.

[Bug #20001]
2024-01-12 17:29:48 +11:00
KJ Tsanaktsidis
25f5b83689 Fix crash when printing RGENGC_DEBUG=5 output from GC
I was trying to debug an (unrelated) issue in the GC, and wanted to turn
on the trace-level GC output by compiling it with -DRGENGC_DEBUG=5.
Unfortunately, this actually causes a crash in newobj_init() because the
code there tries to log the obj_info() of the newly created object.
However, the object is not actually sufficiently set up for some of the
things that obj_info() tries to do:

* The instance variable table for a class is not yet initialized, and
  when using variable-length RVALUES, said ivar table is embedded in
  as-yet unitialized memory after the struct RValue. Attempting to read
  this, as obj_info() does, causes a crash.
* T_DATA variables need to dereference their ->type field to print out
  the underlying C type name, which is not set up until newobj_fill() is
  called.

To fix this, create a new method `obj_info_basic`, which dumps out only
the parts of the object that are valid before the object is fully
initialized.

[Fixes #18795]
2024-01-11 10:44:57 +11:00
Peter Zhu
8940922d18 [DOC] Improve doc for GC.latest_compact_info 2024-01-10 09:46:19 -05:00
Peter Zhu
d9bad91c34 [DOC] Fix docs for GC.compact
GC.compact returns GC.latest_compact_info and not GC.latest_gc_info.
2024-01-07 22:26:12 -05:00
Nobuyoshi Nakada
c30b8ae947
Adjust styles and indents [ci skip] 2024-01-08 00:50:41 +09:00
Rian McGuire
7db35e10c3 Fix GC.measure_total_time regression
Commit 93ac7405b8 introduced a regression
where measurements would still be taken after setting
GC.measure_total_time = false.

Fixes [Bug #20157]
2024-01-06 17:36:35 +11:00
Peter Zhu
70618a48f7 Fix off-by-one error for declarative marking
The for loops for marking and reference updating declaratively marked
TypedData objects did not mark/reference update the very last element.

When RGENGC_CHECK_MODE is turned on, this caused the test in Enumerator
to fail with:

    tool/lib/test/unit/testcase.rb:173:in `rescue in run': failed to allocate memory (NoMemoryError)
2023-12-24 20:37:59 -05:00
HParker
7ef90b3978 Correct free_on_exit env var to free_at_exit 2023-12-20 14:36:32 +09:00
Peter Zhu
32ecda354f Support GC.auto_compact = :empty on debug builds
This commit adds `GC.auto_compact = :empty` which will run
auto-compaction sorting pages by empty slots so the most amount of
objects will be moved. This will make it easier to write tests for
auto-compaction.
2023-12-19 18:29:36 -05:00
Peter Zhu
50d39219a9 Use RICLASS_OWNS_M_TBL_P
It's more consistent with gc_mark_children.
2023-12-19 15:21:28 -05:00
Koichi Sasada
f9a48548cf restore the stack pointer on finalizer
When error on finalizer, the exception will be ignored.
To restart the code, we need to restore the stack pointer.

fix [Bug #20042]
2023-12-19 17:59:49 +09:00
Peter Zhu
f35fec7710 Reset pinned_slots at the beginning of GC
pinned_slots is not being reset every GC, which causes this assertion to
fail:

```
Assertion Failed: gc.c:7076:gc_pin:GET_HEAP_PAGE(obj)->pinned_slots <= GET_HEAP_PAGE(obj)->total_slots
```

This commit changes it to reset it at the beginning of every compaction
GC cycle.
2023-12-18 10:37:21 -05:00
HParker
474b4c42f4 free ractors with ractor_free
Previously with RUBY_FREE_ON_EXIT, ractors where being xfree-ed which is incorrect since they are not xmalloced.
Instead we can free ractors with ractor free during shutdown. This change only effects main ractor freeing when RUBY_FREE_ON_EXIT is set.

Co-authored-by: John Hawthorn <john@hawthorn.email>
2023-12-15 10:31:15 -05:00
Peter Zhu
912016f626 Call obj_free for T_DATA, T_FILE objects on exit
Previously, T_DATA and T_FILE objects did not have their instance
variables freed on exit which would be reported as a memory leak with
RUBY_FREE_ON_EXIT. This commit changes it to use obj_free which also
frees the generic instance variables.

Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
2023-12-14 08:52:32 -05:00
John Hawthorn
d7dad64465 Unlock freelist before assigning
Co-authored-by: Matthew Draper <matthew@trebex.net>
2023-12-13 15:26:52 -08:00
Peter Zhu
f8ddcecbdf [Bug #20061] Clear mark bits when rb_free_on_exit
When compiling with cppflags=-DRGENGC_CHECK_MODE, the following crashes:

```
$ RUBY_FREE_ON_EXIT=1 ./miniruby -e 0
-e: [BUG] obj_free: RVALUE_MARKED(0x0000000103570020 [3LM    ] T_CLASS (anon)) != FALSE
```

This commit clears the mark bits when rb_free_on_exit is enabled.
2023-12-13 10:39:06 -05:00
Koichi Sasada
c4c39082af add flags to rb_postponed_job_preregister
for future extensions.
2023-12-10 15:39:06 +09:00
KJ Tsanaktsidis
f8effa209a Change the semantics of rb_postponed_job_register
Our current implementation of rb_postponed_job_register suffers from
some safety issues that can lead to interpreter crashes (see bug #1991).
Essentially, the issue is that jobs can be called with the wrong
arguments.

We made two attempts to fix this whilst keeping the promised semantics,
but:
  * The first one involved masking/unmasking when flushing jobs, which
    was believed to be too expensive
  * The second one involved a lock-free, multi-producer, single-consumer
    ringbuffer, which was too complex

The critical insight behind this third solution is that essentially the
only user of these APIs are a) internal, or b) profiling gems.

For a), none of the usages actually require variable data; they will
work just fine with the preregistration interface.

For b), generally profiling gems only call a single callback with a
single piece of data (which is actually usually just zero) for the life
of the program. The ringbuffer is complex because it needs to support
multi-word inserts of job & data (which can't be atomic); but nobody
actually even needs that functionality, really.

So, this comit:
  * Introduces a pre-registration API for jobs, with a GVL-requiring
    rb_postponed_job_prereigster, which returns a handle which can be
    used with an async-signal-safe rb_postponed_job_trigger.
  * Deprecates rb_postponed_job_register (and re-implements it on top of
    the preregister function for compatability)
  * Moves all the internal usages of postponed job register
    pre-registration
2023-12-10 15:00:37 +09:00