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

2373 Коммитов

Автор SHA1 Сообщение Дата
NARUSE, Yui 57a0afe209
merge revision(s) 081ee3d35509110f383cb7dd8d1205def0cdd1e8,1c97abaabae6844c861705fd07f532292dcffa74: [Backport #19907] (#10315)
Add memory leak test for eval kwargs

	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-03-21 02:23:21 +00:00
KJ Tsanaktsidis 920c17dc94
Backport #20157 to Ruby 3.3 (#9428)
* 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]

* Add test case for GC.measure_total_time

---------

Co-authored-by: Rian McGuire <rian@rian.id.au>
2024-02-01 04:33:30 +00: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
Adam Hess 6816e8efcf Free everything at shutdown
when the RUBY_FREE_ON_SHUTDOWN environment variable is set, manually free memory at shutdown.

Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
Co-authored-by: Peter Zhu <peter@peterzhu.ca>
2023-12-07 15:52:35 -05:00
Peter Zhu 0dc40bd2b7 Check need_major_gc during GC stress
need_major_gc is set when a major GC is required. However, if
gc_stress_no_major is also set, then it will not actually run a major
GC.

For example, the following script will sometimes crash:

```
GC.stress = 1
50000.times.map { [] }
```

With the following message:

```
[BUG] cannot create a new page after major GC
```
2023-12-07 10:49:06 -05:00
KJ Tsanaktsidis cbc0e0bef0 Fix GC.verify_compaction_references not moving every object
The intention of GC.verify_compaction_references is, I believe, to force
every single movable object to be moved, so that it's possible to debug
native extensions which not correctly updating their references to
objects they mark as movable.

To do this, it doubles the number of allocated pages for each size pool,
and sorts the heap pages so that the free ones are swept first; thus,
every object in an old page should be moved into a free slot in one of
the new pages.

This worked fine until movement of objects _between_ size pools during
compaction was implemented. That causes some problems for
verify_compaction_references:

* We were doubling the number of pages in each size pool, but actually
  if some objects need to move into a _different_ pool, there's no
  guarantee that they'll be enough room in that one.
* It's possible for the sweep & compact cursors to meet in one size pool
  before all the objects that want to move into that size pool from
  another are processed by the compaction.

You can see these problems by changing some of the movement tests in
test_gc_compact.rb to try and move e.g. 50,000 objects instead of
500; the test is not able to actually move all of the objects in a
single compaction run.

To fix this, we do two things in verify_compaction_references:

* Firstly, we add enough pages to every size pool to make them the same
  size. This ensures that their compact cursors will all have space to
  move during compaction (even if that means empty pages are
  pointlessly compacted)
* Then, we examine every object and determine where it _wants_ to be
  compacted into. We use this information to add additional pages to
  each size pool to handle all objects which should live there.

With these two changes, we can move arbitrary amounts of objects into
the correct size pool in a single call to verify_compaction_references.

My _motivation_ for performing this work was to try and fix some test
stability issues in test_gc_compact.rb. I now no longer think that we
actually see this particular bug in rubyci.org, but I also think
verify_compaction_references should do what it says on the tin, so it's
worth keeping.

[Bug #20022]
2023-12-07 10:19:35 -05:00
KJ Tsanaktsidis 5d832d16d9 Add objspace_each_pages to gc.c
This works like objspace_each_obj, except instead of being called with
the start & end address of each page, it's called with the page
structure itself.

[Bug #20022]
2023-12-07 10:19:35 -05:00
Soutaro Matsumoto 4f213ea1ba
Fix SEGV caused by `GC::Profiler.raw_data` (#9122) 2023-12-07 10:37:00 +09:00
Peter Zhu 12e3b07455 Re-embed when removing Object instance variables
Objects with the same shape must always have the same "embeddedness"
(either embedded or heap allocated) because YJIT assumes so. However,
using remove_instance_variable, it's possible that some objects are
embedded and some are heap allocated because it does not re-embed heap
allocated objects.

This commit changes remove_instance_variable to re-embed Object
instance variables when it becomes small enough.
2023-12-06 11:34:07 -05:00
Nobuyoshi Nakada 9c5e1b7189
Fix format specifiers for `size_t` 2023-12-04 10:39:17 +09:00
Peter Zhu b77551adee Remove unneeded local variables 2023-12-01 15:21:01 -05:00
Peter Zhu 80ea7fbad8 Pin embedded shared strings
Embedded shared strings cannot be moved because strings point into the
slot of the shared string. There may be code using the RSTRING_PTR on
the stack, which would pin the string but not pin the shared string,
causing it to move.
2023-12-01 15:04:31 -05:00
Alan Wu fcabe2df39
Remove written-but-never-read `me->def.body.refined.owner`
This also removes aliasing rule violations; the anonymous structs were
distinct types from `rb_method_refined_t`.
2023-11-29 01:41:40 +00:00
Peter Zhu e3875dd0f8 Don't incremental mark when GC stressful
Incremental marking prevents the GC from fully executing, so it may fail
to catch certain bugs.
2023-11-27 11:13:47 -05:00
Peter Zhu 7835ebce97 Set compaction after major GC has been determined
do_full_mark can change in gc_start, so we want to set auto-compaction
only after do_full_mark has been properly set.
2023-11-27 10:23:43 -05:00
Peter Zhu 269c705f93 Fix compaction for generic ivars
When generic instance variable has a shape, it is marked movable. If it
it transitions to too complex, it needs to update references otherwise
it may have incorrect references.
2023-11-24 13:29:04 -05:00
KJ Tsanaktsidis e201b81f79 Mark cc->cme_ for refinement callcaches as well
This is required for the same reason that super CC needs it.
See 36023d5cb7.

Reproducer:

    def cached_foo_callsite(obj) = obj.foo

    class Foo
      def foo = :v1

      module R
        refine Foo do
          def foo = :unused
        end
      end
    end

    obj = Foo.new
    cached_foo_callsite(obj) # set up cc with cme for foo=:v1

    class Foo
      def foo = :v2
    end
    GC.start # cme for foo=:v1 collected, if not reachable by cached_foo_callsite

    cached_foo_callsite(obj)

[Bug #19994]
2023-11-24 13:16:15 -05:00
Peter Zhu 99e1f7b607 Abort GC on shutdown
On large Ruby applications, shutdown may be slow if a major GC has just
started because rb_objspace_call_finalizer completes the GC.

This commit adds gc_abort which discards the mark stack if during
incremental marking and stops sweeping if during lazy sweeping.
2023-11-24 09:28:34 -05:00
Alan Wu 1ffaff884e Allow ivars movement in too_complex RCLASSes to fix crash
Previously, because gc_update_object_references() did not update the
VALUEs in the too_complex ivar st_table for T_CLASS and T_MODULE
objects, GC compaction could finish with corrupted objects.

 - start with `klass`, not too_complex
 - GC incremental step marks `klass` and its ivars
 - ruby code makes `klass` too_complex
 - GC compaction runs and move `klass` ivars, but because `klass` is
   too_complex, its ivars are not updated by gc_update_object_references(),
   leaving T_NONE or T_MOVED objects in the ivar table.

Co-authored-by: Peter Zhu <peter@peterzhu.ca>
2023-11-23 20:30:18 -05:00
Alan Wu 22de08811e Avoid marking IDs in too_complex tables and rename gc_update_tbl_refs()
Marking both keys and values versus marking just values is an important
distinction, but previously, gc_update_tbl_refs() and gc_update_table_refs()
had names that were too similar.

The st_table storing ivars for too_complex T_OBJECTs have IDs as keys,
but we were marking the IDs unnecessary previously, maybe due to the
confusing naming.
2023-11-23 20:30:18 -05:00
Alan Wu ecdb112881 Fix `rp(too_complex_t_object)` tripping assert
Previously, it tripped the assert about too_complex in
ROBJECT_IV_CAPACITY(). This fixes double faults for some crashes and
helps with use during development.
2023-11-23 12:16:57 -05:00
Aaron Patterson 6fce8c7980 Don't try compacting ivars on Classes that are "too complex"
Too complex classes use a hash table to store ivs, and should always pin
their IVs.  We shouldn't touch those classes in compaction.
2023-11-20 16:09:48 -08:00
Peter Zhu ad03320743 Support declarative marked TypedData objects on VWA 2023-11-20 18:59:01 -05:00
Jean Boussier 940f2e7f18 size_pool_idx_for_size: Include debugging info in error message
We ran into that case on our CI, including some sizes would help
debug it much easier.
2023-11-17 14:22:07 +01:00
Jean Boussier f1b95095d6 Revert "Wrap rb_objspace_reachable_objects_from_root with RB_VM_LOCK"
This reverts commit 76dc327eef.
2023-11-13 08:57:57 +01:00
Jean Boussier a1887f4dc2 Revert "Fix crash caused by concurrent ObjectSpace.dump_all calls"
This reverts commit 9a62fd3cba.
2023-11-13 08:57:57 +01:00
KJ Tsanaktsidis 9a62fd3cba Fix crash caused by concurrent ObjectSpace.dump_all calls
Since the callback defined in the objspace module might give up the GVL,
we need to make sure the right cr->mfd value is set back after the GVL
is re-obtained.
2023-11-12 17:50:37 +01:00
KJ Tsanaktsidis 76dc327eef Wrap rb_objspace_reachable_objects_from_root with RB_VM_LOCK
rb_objspace_reachable_objects_from has it too, so I figure it's most
likely required for _from_root as well.
2023-11-12 17:50:37 +01:00
Nobuyoshi Nakada 1fe2bc4b22
RCLASS_EXT is never NULL now 2023-11-11 15:57:44 +09:00
Jean Boussier a9f45aac6e rb_data_free: Fix freeing embedded TypedData
The previous implementation was using the pointer given
by `DATA_PTR` in all cases. But in the case of an embedded
TypedData, that pointer is garbage, we need to use RTYPEDDATA_GET_DATA
to get the proper data pointer.

Co-Authored-By: Étienne Barrié <etienne.barrie@gmail.com>
2023-11-10 15:56:42 +01:00
Peter Zhu 392238e3fd Implement embedded TypedData objects
This commit adds a new flag RUBY_TYPED_EMBEDDABLE that allows the data
of a TypedData object to be embedded after the object itself. This will
improve cache locality and allow us to save the 8 byte data pointer.

Co-Authored-By: Jean Boussier <byroot@ruby-lang.org>
2023-11-07 15:48:06 -05:00
Peter Zhu 38ba040d8b Make every initial size pool shape a root shape
This commit makes every initial size pool shape a root shape and assigns
it a capacity of 0.
2023-11-02 13:42:11 -04:00
Peter Zhu 7979c009a7 Fix bug for removed weak references
rb_darray_foreach gives a pointer to the entry, so we need to deference
it to read the value.
2023-10-27 11:00:12 -04:00
Aaron Patterson a3f66e09f6 geniv objects can become too complex 2023-10-24 10:52:06 -07:00
Jean Boussier e5364ea496 rb_shape_transition_shape_capa: use optimal sizes transitions
Previously the growth was 3(embed), 6, 12, 24, ...

With this change it's now 3(embed), 8, 16, 32, 64, ... by default.

However, since power of two isn't the best size for all allocators,
if `malloc_usable_size` is vailable, we use it to discover the best
offset.

On Linux/glibc 2.35 for instance, the growth will be 3(embed), 7, 15, 31
to avoid wasting 8B per object.

Test program:

```c

size_t test(size_t slots) {
    size_t allocated = slots * VALUE_SIZE;
    void *test_ptr = malloc(allocated);
    size_t wasted = malloc_usable_size(test_ptr) - allocated;
    free(test_ptr);
    fprintf(stderr, "slots = %lu, wasted_bytes = %lu\n", slots, wasted);
    return wasted;
}

int main(int argc, char *argv[]) {
    size_t best_padding = 0;
    size_t padding = 0;
    for (padding = 0; padding <= 2; padding++) {
        size_t wasted = test(8 - padding);
        if (wasted == 0) {
            best_padding = padding;
            break;
        }
    }

    size_t index = 0;
    fprintf(stderr, "=============== naive ================\n");

    size_t list_size = 4;
    for (index = 0; index < 10; index++) {
        test(list_size);
        list_size *= 2;
    }

    fprintf(stderr, "=============== auto-padded (-%lu) ================\n", best_padding);

    list_size = 4;
    for (index = 0; index < 10; index ++) {
        test(list_size - best_padding);
        list_size *= 2;
    }

    fprintf(stderr, "\n\n");
    return 0;
}
```

```
===== glibc ======
slots = 8, wasted_bytes = 8
slots = 7, wasted_bytes = 0
=============== naive ================
slots = 4, wasted_bytes = 8
slots = 8, wasted_bytes = 8
slots = 16, wasted_bytes = 8
slots = 32, wasted_bytes = 8
slots = 64, wasted_bytes = 8
slots = 128, wasted_bytes = 8
slots = 256, wasted_bytes = 8
slots = 512, wasted_bytes = 8
slots = 1024, wasted_bytes = 8
slots = 2048, wasted_bytes = 8
=============== auto-padded (-1) ================
slots = 3, wasted_bytes = 0
slots = 7, wasted_bytes = 0
slots = 15, wasted_bytes = 0
slots = 31, wasted_bytes = 0
slots = 63, wasted_bytes = 0
slots = 127, wasted_bytes = 0
slots = 255, wasted_bytes = 0
slots = 511, wasted_bytes = 0
slots = 1023, wasted_bytes = 0
slots = 2047, wasted_bytes = 0
```

```
==========  jemalloc =======
slots = 8, wasted_bytes = 0
=============== naive ================
slots = 4, wasted_bytes = 0
slots = 8, wasted_bytes = 0
slots = 16, wasted_bytes = 0
slots = 32, wasted_bytes = 0
slots = 64, wasted_bytes = 0
slots = 128, wasted_bytes = 0
slots = 256, wasted_bytes = 0
slots = 512, wasted_bytes = 0
slots = 1024, wasted_bytes = 0
slots = 2048, wasted_bytes = 0
=============== auto-padded (-0) ================
slots = 4, wasted_bytes = 0
slots = 8, wasted_bytes = 0
slots = 16, wasted_bytes = 0
slots = 32, wasted_bytes = 0
slots = 64, wasted_bytes = 0
slots = 128, wasted_bytes = 0
slots = 256, wasted_bytes = 0
slots = 512, wasted_bytes = 0
slots = 1024, wasted_bytes = 0
slots = 2048, wasted_bytes = 0
```
2023-10-23 09:33:15 +02:00
Yusuke Endoh 833c930bd6 Remove unneeded checks
Follow up of 591336a0f2
2023-10-16 03:58:30 +09:00
Nobuyoshi Nakada a075c55d0c Manage `rb_strterm_t` without imemo 2023-10-14 11:08:43 +09:00
HParker c74dc8b4af Use reference counting to avoid memory leak in kwargs
Tracks other callinfo that references the same kwargs and frees them when all references are cleared.

[bug #19906]

Co-authored-by: Peter Zhu <peter@peterzhu.ca>
2023-10-01 10:55:19 -04:00
Nobuyoshi Nakada ac244938e8 Dump backtraces to an arbitrary stream 2023-09-25 22:57:28 +09:00