Commit graph

604 commits

Author SHA1 Message Date
Peter Zhu
98b36f6f36 Use rb_gc_vm_weak_table_foreach for reference updating
We can use rb_gc_vm_weak_table_foreach for reference updating of weak tables
in the default GC.
2025-01-27 10:28:36 -05:00
Peter Zhu
89240eb2fb Add generic ivar reference updating step
Previously, generic ivars worked differently than the other global tables
during compaction. The other global tables had their references updated
through iteration during rb_gc_update_vm_references. Generic ivars updated
the keys when the object moved and updated the values while reference
updating the object. This is inefficient as this required one lookup for
every moved object and one lookup for every object with generic ivars.

Instead, this commit changes it to iterate over the generic ivar table to
update both the keys and values.
2025-01-22 08:54:52 -05:00
Peter Zhu
5a448a87fc Remove dead function rb_func_proc_new 2025-01-20 10:31:36 -05:00
Aaron Patterson
50c2c4bdde Make rb_vm_insns_count a thread local variable
`rb_vm_insns_count` is a global variable used for reporting YJIT
statistics. It is a counter that tallies the number of interpreter
instructions that have been executed, this way we can approximate how
much time we're spending in YJIT compared to the interpreter.

Unfortunately keeping this statistic means that every instruction
executed in the interpreter loop must increment the counter. Normally
this isn't a problem, but in multi-threaded situations (when Ractors are
used), incrementing this counter can become quite costly due to page
caching issues.

Additionally, since there is no locking when incrementing this global,
the count can't really make sense in a multi-threaded environment.

This commit changes `rb_vm_insns_count` to a thread local. That way each
Ractor has it's own copy of the counter and incrementing the counter
becomes quite cheap. Of course this means that in multi-threaded
situations, the value doesn't really make sense (but it didn't make
sense before because of the lack of locking).

The counter is used for YJIT statistics, and since YJIT is basically
disabled when Ractors are in use, I don't think we care about
inaccuracies (for the time being). We can revisit this counter when we
give YJIT multi-threading support, but for the time being this commit
restores multi-threaded performance.

To test this, I used the benchmark in [Bug #20489].

Here is the performance on Ruby 3.2:

```
$ time RUBY_MAX_CPU=12 ./miniruby -v ../test.rb 8 8
ruby 3.2.0 (2022-12-25 revision a528908271) [x86_64-linux]
[0...1, 1...2, 2...3, 3...4, 4...5, 5...6, 6...7, 7...8]
../test.rb:43: warning: Ractor is experimental, and the behavior may change in future versions of Ruby! Also there are many implementation issues.

________________________________________________________
Executed in    2.53 secs    fish           external
   usr time   19.86 secs  370.00 micros   19.86 secs
   sys time    0.02 secs  320.00 micros    0.02 secs
```

We can see the regression in performance on the master branch:

```
$ time RUBY_MAX_CPU=12 ./miniruby -v ../test.rb 8 8
ruby 3.5.0dev (2025-01-10T16:22:26Z master 4a2702dafb) +PRISM [x86_64-linux]
[0...1, 1...2, 2...3, 3...4, 4...5, 5...6, 6...7, 7...8]
../test.rb:43: warning: Ractor is experimental, and the behavior may change in future versions of Ruby! Also there are many implementation issues.

________________________________________________________
Executed in   24.87 secs    fish           external
   usr time  195.55 secs    0.00 micros  195.55 secs
   sys time    0.00 secs  716.00 micros    0.00 secs
```

Here are the stats after this commit:

```
$ time RUBY_MAX_CPU=12 ./miniruby -v ../test.rb 8 8
ruby 3.5.0dev (2025-01-10T20:37:06Z tl 3ef0432779) +PRISM [x86_64-linux]
[0...1, 1...2, 2...3, 3...4, 4...5, 5...6, 6...7, 7...8]
../test.rb:43: warning: Ractor is experimental, and the behavior may change in future versions of Ruby! Also there are many implementation issues.

________________________________________________________
Executed in    2.46 secs    fish           external
   usr time   19.34 secs  381.00 micros   19.34 secs
   sys time    0.01 secs  321.00 micros    0.01 secs
```

[Bug #20489]
2025-01-10 13:39:21 -08:00
Nobuyoshi Nakada
4a2702dafb
Remove stale declaration for modular GC 2025-01-11 01:22:26 +09:00
Peter Zhu
62a1528020 Pass allocation size to rb_imemo_new
This would allow imemo to take advantage of VWA and allocate sizes larger
than RVALUE (40 bytes).
2025-01-08 09:11:59 -05:00
Peter Zhu
d0f9f3e2c6 Remove IMEMO_DEBUG
The code path hasn't compiled for almost a year, since 330830dd1a,
so probably nobody uses it.
2025-01-07 11:01:08 -05:00
Peter Zhu
34ee062d74 Remove dead function rb_struct_const_heap_ptr 2025-01-03 17:02:50 -05:00
Nobuyoshi Nakada
fb18bb183c
[Bug #20989] Ripper: Pass compile_error
For the universal parser, `rb_parser_reg_fragment_check` function is
shared between the parser and ripper.  However `parser_params` struct
is partially different, and `compile_error` function depends on that
part indirectly.
2024-12-28 11:25:57 +09:00
Nobuyoshi Nakada
7b2ae8df90
[Bug #20969] Pass assignable from ripper
For the universal parser, `rb_reg_named_capture_assign_iter_impl`
function is shared between the parser and ripper.  However
`parser_params` struct is partially different, and `assignable`
function depends on that part indirectly.
2024-12-19 23:20:09 +09:00
Peter Zhu
a58675386c Prefix asan_poison_object with rb 2024-12-19 09:14:34 -05:00
Peter Zhu
a72717675f Export asan_poison_object 2024-12-19 09:14:34 -05:00
Peter Zhu
c37bdfa531 Make asan_poison_object poison the whole slot
This change poisons the whole slot of the object rather than just the flags.
This allows ASAN to find any reads/writes into the slot after it has been
freed.
2024-12-19 09:14:34 -05:00
Alan Wu
2102fe32ff Detect ASAN when using older GCC versions
Newer GCCs have __has_feature and older ones have
__SANITIZE_ADDRESS__[1]. Relevant since ASAN with GCC 11 on the popular
Ubuntu Jammy failed to build previously.

[1]: https://gcc.gnu.org/onlinedocs/gcc-4.8.0/cpp/Common-Predefined-Macros.html
2024-12-16 17:11:36 -05:00
Peter Zhu
516a6cd1ad Check whether object is valid in allocation_info_tracer_compact
When reference updating ObjectSpace.trace_object_allocations, we need to
check whether the object is valid or not because it does not mark the
object so the object may be dead. This can cause a segmentation fault
if the object is on a free heap page.

For example, the following script crashes:

    require "objspace"

    objs = []
    ObjectSpace.trace_object_allocations do
      1_000_000.times do
        objs << Object.new
      end
    end

    objs = nil

    # Free pages that the objs were on
    GC.start

    # Run compaction and check that it doesn't crash
    GC.compact
2024-12-16 12:24:24 -05:00
Peter Zhu
92dd9734a9 Fix use-after-free in ep in Proc#dup for ifunc procs
[Bug #20950]

ifunc proc has the ep allocated in the cfunc_proc_t which is the data of
the TypedData object. If an ifunc proc is duplicated, the ep points to
the ep of the source object. If the source object is freed, then the ep
of the duplicated object now points to a freed memory region. If we try
to use the ep we could crash.

For example, the following script crashes:

    p = { a: 1 }.to_proc
    100.times do
      p = p.dup
      GC.start
      p.call
    rescue ArgumentError
    end

This commit changes ifunc proc to also duplicate the ep when it is duplicated.
2024-12-13 10:10:03 -05:00
Peter Zhu
ca2d19d4e5 Implement rb_bug_without_die 2024-12-12 14:07:56 -05:00
Nobuyoshi Nakada
267ecf5f02 Add rb_warn_reserved_name_at 2024-12-12 17:45:06 +09:00
Peter Zhu
c45503f957 Add rb_gc_impl_active_gc_name to gc/gc_impl.h 2024-12-06 10:22:03 -05:00
Peter Zhu
eedb30d385 Use rb_gc_enable/rb_gc_disable_no_rest instead of ruby_disable_gc
We should use the rb_gc_enable/rb_gc_disable_no_rest APIs instead of
directly setting the ruby_disable_gc variable.
2024-12-05 16:21:37 -05:00
Peter Zhu
ce1ad1b816 Standardize on the name "modular GC"
We have name fragmentation for this feature, including "shared GC",
"modular GC", and "external GC". This commit standardizes the feature
name to "modular GC" and the implementation to "GC library".
2024-12-05 10:33:26 -05:00
Peter Zhu
3c91a1e5fd Fix ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS for MSAN
There's no case for when RUBY_MSAN_ENABLED, so the macro ends up doing
nothing when it should instead have __attribute__((__no_sanitize__("memory"))).
2024-12-04 14:29:24 -05:00
Randy Stauner
1dd40ec18a
Optimize instructions when creating an array just to call include? (#12123)
* Add opt_duparray_send insn to skip the allocation on `#include?`

If the method isn't going to modify the array we don't need to copy it.
This avoids the allocation / array copy for things like `[:a, :b].include?(x)`.

This adds a BOP for include? and tracks redefinition for it on Array.

Co-authored-by: Andrew Novoselac <andrew.novoselac@shopify.com>

* YJIT: Implement opt_duparray_send include_p

Co-authored-by: Andrew Novoselac <andrew.novoselac@shopify.com>

* Update opt_newarray_send to support simple forms of include?(arg)

Similar to opt_duparray_send but for non-static arrays.

* YJIT: Implement opt_newarray_send include_p

---------

Co-authored-by: Andrew Novoselac <andrew.novoselac@shopify.com>
2024-11-26 14:31:08 -05:00
Matt Valentine-House
551be8219e Place all non-default GC API behind USE_SHARED_GC
So that it doesn't get included in the generated binaries for builds
that don't support loading shared GC modules

Co-Authored-By: Peter Zhu <peter@peterzhu.ca>
2024-11-25 13:05:23 +00:00
Kunshan Wang
8ae7c22972 Annotate anonymous mmap
Use PR_SET_VMA_ANON_NAME to set human-readable names for anonymous
virtual memory areas mapped by `mmap()` when compiled and run on Linux
5.17 or higher.  This makes it convenient for developers to debug mmap.
2024-11-21 13:48:05 -05:00
Samuel Williams
9c268302bf
Introduce Fiber::Scheduler#blocking_operation_wait. (#12016)
Redirect `rb_nogvl` blocking operations to the fiber scheduler if possible
to prevent stalling the event loop.

[Feature #20876]
2024-11-20 19:40:17 +13:00
Matt Valentine-House
ee290c94a3 Include the currently active GC in RUBY_DESCRIPTION
This will add +MOD_GC to the version string and Ruby description when
Ruby is compiled with shared gc support.

When shared GC support is compiled in and a GC module has been loaded
using RUBY_GC_LIBRARY, the version string will include the name of
the currently active GC as reported by the rb_gc_active_gc_name function
in the form

+MOD_GC[gc_name]

[Feature #20794]
2024-11-14 10:46:36 +00:00
Randy Stauner
beafae9750
YJIT: Specialize String#[] (String#slice) with fixnum arguments (#12069)
* YJIT: Specialize `String#[]` (`String#slice`) with fixnum arguments

String#[] is in the top few C calls of several YJIT benchmarks:
liquid-compile rubocop mail sudoku

This speeds up these benchmarks by 1-2%.

* YJIT: Try harder to get type info for `String#[]`

In the large generated code of the mail gem the context doesn't have
the type info.  In that case if we peek at the stack and add a guard
we can still apply the specialization
and it speeds up the mail benchmark by 5%.

Co-authored-by: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@shopify.com>
Co-authored-by: Takashi Kokubun (k0kubun) <takashikkbn@gmail.com>

---------

Co-authored-by: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@shopify.com>
Co-authored-by: Takashi Kokubun (k0kubun) <takashikkbn@gmail.com>
2024-11-13 12:25:09 -05:00
Jean byroot Boussier
6deeec5d45
Mark strings returned by Symbol#to_s as chilled (#12065)
* Use FL_USER0 for ELTS_SHARED

This makes space in RString for two bits for chilled strings.

* Mark strings returned by `Symbol#to_s` as chilled

[Feature #20350]

`STR_CHILLED` now spans on two user flags. If one bit is set it
marks a chilled string literal, if it's the other it marks a
`Symbol#to_s` chilled string.

Since it's not possible, and doesn't make much sense to include
debug info when `--debug-frozen-string-literal` is set, we can't
include allocation source, but we can safely include the symbol
name in the warning message, making it much easier to find the source
of the issue.

Co-Authored-By: Étienne Barrié <etienne.barrie@gmail.com>

---------

Co-authored-by: Étienne Barrié <etienne.barrie@gmail.com>
Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
2024-11-13 09:20:00 -05:00
Jean Boussier
fae86a701e string.c: Directly create strings with the correct encoding
While profiling msgpack-ruby I noticed a very substantial amout of time
spent in `rb_enc_associate_index`, called by `rb_utf8_str_new`.

On that benchmark, `rb_utf8_str_new` is 33% of the total runtime,
in big part because it cause GC to trigger often, but even then
`5.3%` of the total runtime is spent in `rb_enc_associate_index`
called by `rb_utf8_str_new`.

After closer inspection, it appears that it's performing a lot of
safety check we can assert we don't need, and other extra useless
operations, because strings are first created and filled as ASCII-8BIT
and then later reassociated to the desired encoding.

By directly allocating the string with the right encoding, it allow
to skip a lot of duplicated and useless operations.

After this change, the time spent in `rb_utf8_str_new` is down
to `28.4%` of total runtime, and most of that is GC.
2024-11-13 13:32:32 +01:00
Nobuyoshi Nakada
edb1c8215d Add integer overflow check macros for add/sub as well as mul 2024-11-09 00:08:03 +09:00
Koichi Sasada
97aaf6f760 introduce rb_ec_check_ints()
to avoid TLS issue with N:M threads.
2024-11-08 18:02:46 +09:00
Koichi Sasada
c8297c3eed interrupt_exec
introduce
- rb_threadptr_interrupt_exec
- rb_ractor_interrupt_exec

to intercept the thread/ractor execution.
2024-11-08 18:02:46 +09:00
Matt Valentine-House
1634280e1c Fix shared GC with -DRUBY_DEBUG
RUBY_DEBUG enables ractor assertions, which sets up some space at the
end of each RVALUE to store the associated ractor ID. We need to make
sure the function that does this is visible to shared GC libraries.
2024-10-24 16:08:46 +01:00
Étienne Barrié
257f78fb67 Show where mutated chilled strings were allocated
[Feature #20205]

The warning now suggests running with --debug-frozen-string-literal:

```
test.rb:3: warning: literal string will be frozen in the future (run with --debug-frozen-string-literal for more information)
```

When using --debug-frozen-string-literal, the location where the string
was created is shown:

```
test.rb:3: warning: literal string will be frozen in the future
test.rb:1: info: the string was created here
```

When resurrecting strings and debug mode is not enabled, the overhead is a simple FL_TEST_RAW.
When mutating chilled strings and deprecation warnings are not enabled,
the overhead is a simple warning category enabled check.

Co-authored-by: Jean Boussier <byroot@ruby-lang.org>
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
Co-authored-by: Jean Boussier <byroot@ruby-lang.org>
2024-10-21 12:33:02 +02:00
Alan Wu
11e7ab79de
Remove 1 allocation in Enumerable#each_with_index (#11868)
* Remove 1 allocation in Enumerable#each_with_index

Previously, each call to Enumerable#each_with_index allocates 2
objects, one for the counting index, the other an imemo_ifunc passed
to `self.each` as a block.

Use `struct vm_ifunc::data` to hold the counting index directly to
remove 1 allocation.

* [DOC] Brief summary for usages of `struct vm_ifunc`
2024-10-11 10:22:44 -04:00
Alan Wu
25c4629ec3 Remove duplicate struct declaration 2024-10-10 12:32:47 -04:00
Nobuyoshi Nakada
8ba2c3109c Fix extra semicolon outside of a function in NO_SANITIZE
```
internal/sanitizers.h:57:26: error: ISO C does not allow extra ‘;’ outside of a function [-Wpedantic]
   57 |     COMPILER_WARNING_PUSH; \
      |                          ^
```

and so many.

Remove semicolons following pragma, and repeat the given declaration
at the end to consume a semicolon following the macro call.  As many
`NO_SANITIZE` calls including bigdecimal that is a gem have a trailing
semicolon, it was not able to move the semicolon inside `NO_SANITIZE`.
2024-10-08 23:29:49 +09:00
Nobuyoshi Nakada
d8b64eac55 rb_fix_mul_fix needs internal/bits.h for MUL_OVERFLOW_FIXNUM_P 2024-10-08 23:29:49 +09:00
Samuel Williams
c50298d7d4
Introduce rb_io_blocking_region which takes struct rb_io argument. (#11795)
This does not change any actual behaviour, but provides a choke point for blocking IO operations.

* Update `IO::Buffer` to use `rb_io_blocking_region`.

* Update `File` to use `rb_io_blocking_region`.

* Update `IO` to use `rb_io_blocking_region`.
2024-10-05 15:10:12 +13:00
Matt Valentine-House
8e7df4b7c6 Rename size_pool -> heap
Now that we've inlined the eden_heap into the size_pool, we should
rename the size_pool to heap. So that Ruby contains multiple heaps, with
different sized objects.

The term heap as a collection of memory pages is more in memory
management nomenclature, whereas size_pool was a name chosen out of
necessity during the development of the Variable Width Allocation
features of Ruby.

The concept of size pools was introduced in order to facilitate
different sized objects (other than the default 40 bytes). They wrapped
the eden heap and the tomb heap, and some related state, and provided a
reasonably simple way of duplicating all related concerns, to provide
multiple pools that all shared the same structure but held different
objects.

Since then various changes have happend in Ruby's memory layout:

* The concept of tomb heaps has been replaced by a global free pages list,
  with each page having it's slot size reconfigured at the point when it
  is resurrected
* the eden heap has been inlined into the size pool itself, so that now
  the size pool directly controls the free_pages list, the sweeping
  page, the compaction cursor and the other state that was previously
  being managed by the eden heap.

Now that there is no need for a heap wrapper, we should refer to the
collection of pages containing Ruby objects as a heap again rather than
a size pool
2024-10-03 21:20:09 +01:00
Nobuyoshi Nakada
3e1021b144 Make default parser enum and define getter/setter 2024-10-02 20:43:40 +09:00
Peter Zhu
407f8b8716 Fix memory leak in Ripper for indented heredocs
The allocated parser string is never freed, which causes a memory leak.

The following code leaks memory:

    Ripper.sexp_raw(DATA.read)

    __END__
    <<~EOF
      a
        #{1}
      a
    EOF
2024-09-25 08:56:14 -04:00
KJ Tsanaktsidis
02b36f7572 Unpoison page->freelist before trying to assert on it
Otherwise trying to deref the pointer can cause an ASAN crash, even
though the only reason we're dereferencing it is so that we can assert
on it.
2024-09-23 10:11:54 +10:00
S-H-GAMELINKS
95d26ee41e Reuse dedent_string function in rb_ruby_ripper_dedent_string function
This change is reduce Ruby C API dependency for Universal Parser.
Reuse dedent_string functions in rb_ruby_ripper_dedent_string functions and remove dependencies on rb_str_modify and rb_str_set_len from the parser.
2024-09-22 12:22:20 +09:00
KJ Tsanaktsidis
e08d5239b6 Ensure fiber scheduler is woken up when close interrupts read
If one thread is reading and another closes that socket, the close
blocks waiting for the read to abort cleanly. This ensures that Ruby is
totally done with the file descriptor _BEFORE_ we tell the OS to close
and potentially re-use it.

When the read is correctly terminated, the close should be unblocked.
That currently works if closing is happening on a thread, but if it's
happening on a fiber with a fiber scheduler, it does NOT work.

This patch ensures that if the close happened in a fiber scheduled
thread, that the scheduler is notified that the fiber is unblocked.

[Bug #20723]
2024-09-17 10:11:44 +10:00
Peter Zhu
1e53e46275 Don't export unnecessary string functions
These functions are not used publicly, so we don't need to export them.
2024-09-16 14:38:49 -04:00
Kevin Newton
ea2af5782d Switch the default parser from parse.y to Prism
This commit switches the default parser to Prism. There are a
couple of additional changes related to this that are a part of
this as well to make this happen.

* Switch the default parser in parse.h
* Remove the Prism-specific workflow and add a parse.y-specific
  workflow to CI so that it continues to be tested
* Update a few test exclusions since Prism has the correct
  behavior but parse.y doesn't per
  https://bugs.ruby-lang.org/issues/20504.
* Skips a couple of tests on RBS which are failing because they
  are using RubyVM::AbstractSyntaxTree.of.

Fixes [Feature #20564]
2024-09-12 13:43:04 -04:00
Étienne Barrié
bf9879791a Optimized instruction for Hash#freeze
If a Hash which is empty or only using literals is frozen, we detect
this as a peephole optimization and change the instructions to be
`opt_hash_freeze`.

[Feature #20684]

Co-authored-by: Jean Boussier <byroot@ruby-lang.org>
2024-09-05 12:46:02 +02:00
Étienne Barrié
a99707cd9c Optimized instruction for Array#freeze
If an Array which is empty or only using literals is frozen, we detect
this as a peephole optimization and change the instructions to be
`opt_ary_freeze`.

[Feature #20684]

Co-authored-by: Jean Boussier <byroot@ruby-lang.org>
2024-09-05 12:46:02 +02:00