Commit graph

21005 commits

Author SHA1 Message Date
Jeremy Evans
353fa6f0ba Avoid allocation for positional splat for literal array keyword argument
If all nodes in the array are safe, then it is safe to avoid
allocation for the positional splat:

```ruby
m(*a, kw: [:a])   # Safe
m(*a, kw: [meth]) # Unsafe
```

This avoids an unnecessary allocation in a Rails method call.
Details: https://github.com/rails/rails/pull/54949/files#r2052645431
2025-06-22 06:43:13 +09:00
Jean Boussier
edbd9ed468 variable.c: avoid out of bound write in generic_field_set
[Bug #21445]
2025-06-21 14:40:40 +01:00
Jeremy Evans
1d94a9e1a4 Fix handling of PM_CONSTANT_PATH_NODE node in keyword arguments with ARGS_SPLAT
This was handled correctly in parse.y (NODE_COLON2), but not in
prism. This wasn't caught earlier, because I only added tests for
the optimized case and not the unoptimized case. Add tests for
the unoptimized case.

In code terms:

```ruby
m(*a, kw: lvar::X)     # Does not require allocation for *a
m(*a, kw: method()::X) # Requires allocation for *a
```

This commit fixes the second case when prism is used.
2025-06-21 08:46:24 +09:00
Kazuki Yamaguchi
112ba70647 [ruby/openssl] ssl: add SSLContext#sigalgs= and #client_sigalgs=
Add methods for setting supported signature algorithms, corresponding
to SSL_CTX_set1_sigalgs_list() and SSL_CTX_set1_client_sigalgs_list(),
respectively.

6bbe58c492

Co-authored-by: Markus Jung <markus.jung@vivavis.com>
2025-06-20 17:58:38 +00:00
Nobuyoshi Nakada
d9efc56c16 [ruby/io-console] Ignore ^C at interrupt
It's something we don't expect and might be coming from somewhere
else.

f0646b2b6a
2025-06-20 09:39:29 +00:00
Alan Wu
34eaa6418e ZJIT: Add dupn support 2025-06-19 23:29:37 +09:00
Hiroshi SHIBATA
d4ed7eb1ad
Relax delta value
4439745154

```
    1) Failure:
  TestLastThread#test_last_thread [/Users/runner/work/ruby/ruby/src/test/-ext-/gvl/test_last_thread.rb:18]:
  Expected |1.0 - 1.167141| (0.16714099999999998) to be <= 0.16.
```
2025-06-19 16:49:28 +09:00
David Rodríguez
4245d522b2
[rubygems/rubygems] Allow enabling "Bundler 3 mode" more easily
Currently to test Bundler 3 mode we have to actually edit the version
file to simulate we're running a future version. This is inconvenient.

Instead, allow passing an environment variable, `BUNDLER_3_MODE`, to set
the "working mode" Bundler should use.

This can now be set easily by end users to enable them to try out the
changes in the future version and give us feedback.

It's unclear how version auto-switching should work when this
environment variable is set, so the auto-switching feature will be
disabled in that case.

4e92e9b209
2025-06-19 10:23:36 +09:00
Daniel Colson
3290d3d7f0
ZJIT: Support invokebuiltin opcodes (#13632)
* `invokebuiltin`
* `invokebuiltin_delegate`
* `invokebuiltin_delegate_leave`

These instructions all call out to a C function, passing EC, self, and
some number of arguments. `invokebuiltin` gets the arguments from the
stack, whereas the `_delegate` instructions use a subset of the locals.

`opt_invokebuiltin_delegate_leave` has a fast path for `leave`, but I'm
not sure we need to do anything special for that here (FWIW YJIT appears
to treat the two delegate instructions the same).
2025-06-18 15:58:34 -07:00
Yusuke Endoh
b7cb29b6b2 Add a test for the previous commit 2025-06-18 14:51:56 +09:00
Jean Boussier
cd9f447be2 Refactor generic fields to use T_IMEMO/fields objects.
Followup: https://github.com/ruby/ruby/pull/13589

This simplify a lot of things, as we no longer need to manually
manage the memory, we can use the Read-Copy-Update pattern and
avoid numerous race conditions.

Co-Authored-By: Étienne Barrié <etienne.barrie@gmail.com>
2025-06-17 15:28:05 +02:00
Alan Wu
0933400f45 ZJIT: Add codegen (and FrameState) for GetConstPath
Issue a call to rb_vm_opt_getconstant_path() like the interpreter, but
since that allocates the IC, we need to save the PC before calling. Add
FrameState to GetConstPath to get access to the PC.
2025-06-17 20:51:58 +09:00
Daniel Colson
01ff17fa40 ZJIT: Parse opt freeze insns to HIR
* `opt_hash_freeze`
* `opt_ary_freeze`
* `opt_str_freeze`
* `opt_str_uminus`

Similar to `opt_neq`, but there are no args for `freeze`

Co-authored-by: ywenc <ywenc@github.com>
Co-authored-by: Max Bernstein <max@bernsteinbear.com>
2025-06-17 20:35:47 +09:00
Nobuyoshi Nakada
9e5c74f219 [ruby/prism] [DOC] Fix a typo in comment
ruby/ruby#13636

e13d4f19db

Co-Authored-By: Tim Smith <tsmith84@gmail.com>
2025-06-17 11:18:05 +00:00
David Rodríguez
0a62e82ac4
[rubygems/rubygems] Fix gem install sometimes compiling the wrong source files
If a previous copy of a gem is already installed, RubyGems will not
reinstall the gem but only recompile its extensions. This seems like a
good idea, but only if the gem is being installed from the registry.

If we are installing a locally built package, then the package should be
completely reinstalled and extensions compiled from the sources in the
locally built package, not from the sources in the previous
installation.

1c282d98d5
2025-06-17 15:09:34 +09:00
David Rodríguez
0c2f0ffa60
[rubygems/rubygems] Refactor some logic to create extconf files for tests
9a859078ab
2025-06-17 15:09:34 +09:00
David Rodríguez
fadcee3ba0
[rubygems/rubygems] Use Dir.chdir with a block
I don't see any warnings.

395df777a2
2025-06-17 15:09:34 +09:00
Kasumi Hanazuki
8aac19d598 io_buffer: Reimplement dcompact for IO::Buffer
The `source` field in IO::Buffer can have a String or an IO::Buffer
object, if not nil.

- When the `source` is a String object. The `base` field points to the
  memory location of the String content, which can be embedded in
  RSTRING, and in that case, GC compaction can move the memory region
  along with the String object.

  Thus, IO::Buffer needs to pin the `source` object to prevent `base`
  pointer from becoming invalid.

- When the `source` is an IO::Buffer, then `base` is a pointer to a
  malloced or mmapped memory region, managed by the source IO::Buffer.
  In this case, we don't need to pin the source IO::Buffer object,
  since the referred memory region won't get moved by GC.

Closes: [Bug #21210]
2025-06-17 07:57:02 +02:00
Daniel Colson
b1410c1c75 ZJIT: Add codegen for StringCopy
Prior to this commit we compiled `putstring` and `putchilledstring` to
`StringCopy`, but then failed to compile past HIR.

This commit adds codegen for `StringCopy` to call `rb_ec_str_ressurrect`
as the VM does for these instructions.
2025-06-17 08:20:07 +09:00
Benoit Daloze
2956573b09 Add test for IO::Buffer.for(frozen_string) {} and omit rb_str_{,un}locktmp in that case 2025-06-16 22:59:10 +02:00
Stan Lo
cce4bfdca9
ZJIT: Add support for putspecialobject (#13565)
* ZJIT: Add support for putspecialobject

* Address feedback

* Update tests

* Adjust the indentation of a Ruby test

---------

Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com>
2025-06-16 12:24:33 -07:00
Nobuyoshi Nakada
260ac23a53
Use success option to check if the process failed 2025-06-16 19:20:48 +09:00
Nobuyoshi Nakada
f0371efbd8
Suppress stderr output in TestRubyOptions#assert_segv
It is checked against the given `list`, do not print the same output
twice.
2025-06-16 19:18:11 +09:00
Nobuyoshi Nakada
85e61eac85
Use the message given to TestRubyOptions#assert_segv 2025-06-16 19:16:28 +09:00
Dmitry Dygalo
022c18b60d [ruby/date] [Bug #21436] check for fixnum lower bound in m_ajd
Issue - https://bugs.ruby-lang.org/issues/21436

Apparently, the lower bound check is missing, which results in overflow & wrapping later on in RB_INT2FIX

Signed-off-by: Dmitry Dygalo <dmitry.dygalo@workato.com>

67d75e8423
2025-06-15 16:12:45 +00:00
Dmitry Dygalo
c1877d431e [ruby/date] [Bug #21437] Date#hash for large years
Addresses https://bugs.ruby-lang.org/issues/21437

Signed-off-by: Dmitry Dygalo <dmitry.dygalo@workato.com>

31f07bc576
2025-06-15 16:11:06 +00:00
Nobuyoshi Nakada
9a840fd2d4
Relax the criteria of flaky weak_references count test 2025-06-15 23:59:47 +09:00
Nobuyoshi Nakada
a259ce406f
Simplify weak_references count test initialization
Using an enumerator does not resolve the intermittent failures: 100+
failures in 10,000 iterations.
2025-06-15 23:59:47 +09:00
ydah
d60144a490 Implement COLON3 NODE locations 2025-06-15 22:37:20 +09:00
ydah
c584790bde Implement COLON2 NODE locations 2025-06-15 22:37:20 +09:00
John Hawthorn
c88c2319a8 Skip test_exivar_resize_with_compaction_stress on s390x 2025-06-14 21:41:29 -07:00
John Hawthorn
5342d9130b Fix generic_ivar_set_shape_field for table rebuild
[Bug #21438]

Previously GC could trigger a table rebuild of the generic fields
st_table in the middle of calling the st_update callback. This could
cause entries to be reallocated or rearranged and the update to be for
the wrong entry.

This commit adds an assertion to make that case easier to detect, and
replaces the st_update with a separate st_lookup and st_insert.

Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
Co-authored-by: Jean Boussier <byroot@ruby-lang.org>
2025-06-13 23:29:41 -07:00
Jean Boussier
74cdf8727e Remove test_object_id_race_free_with_stress_compact
This test was written for another implementation of `#object_id`
which had complex interations with GC, that's not the case of
the implementation that was actually merged.
2025-06-14 07:55:43 +02:00
Misaki Shioi
c45c600e22
Add open_timeout as an overall timeout option for Socket.tcp (#13368)
* Add `open_timeout` as an overall timeout option for `Socket.tcp`

[Background]
Currently, `TCPSocket.new` and `Socket.tcp` accept two kind of timeout options:
- `resolv_timeout`, which controls the timeout for DNS resolution
- `connect_timeout`, which controls the timeout for the connection attempt

With the introduction of Happy Eyeballs Version 2 (as per [RFC 8305](https://datatracker.ietf.org/doc/html/rfc8305)) in[ Feature #20108](https://bugs.ruby-lang.org/issues/20108) and [Feature #20782](https://bugs.ruby-lang.org/issues/20782), both address resolution and connection attempts are now parallelized.
As a result, the sum of `resolv_timeout` and `connect_timeout` no longer represents the total timeout duration. This is because, in HEv2, name resolution and connection attempts are performed concurrently, causing the two timeouts to overlap.

Example:
When `resolv_timeout: 200ms` and `connect_timeout: 100ms` are set:
1. An IPv6 address  is resolved after the method starts immediately (IPv4 is still being resolved).
2. A connection attempt is initiated to the IPv6 address
3. After 100ms, `connect_timeout` is exceeded. However, since `resolv_timeout` still has 100ms left, the IPv4 resolution continues.
4. After 200ms from the start, the method raises a `resolv_timeout` error.

In this case, the total elapsed time before a timeout is 200ms, not the expected 300ms (100ms + 200ms).

Furthermore, in HEv2, connection attempts are also parallelized.
It starts a new connection attempts every 250ms for resolved addresses. This makes the definition of `connect_timeout` even more ambiguous—specifically, it becomes unclear from which point the timeout is counted.

Additionally, these methods initiate new connection attempts every 250ms (Connection Attempt Delay) for each candidate address, thereby parallelizing connection attempts. However, this behavior makes it unclear from which point in time the connect_timeout is actually measured.
Currently, a `connect_timeout` is raised only after the last connection attempt exceeds the timeout.

Example:
When `connect_timeout: 100ms` is set and 3 address candidates:
1. Start a connection attempt to the address `a`
2. 250ms after step 1, start a new connection attempt to the address `b`
3. 500ms after step 1, start a new connection attempt to the address `c`
4. 1000ms after step 3 (1000ms after starting the connection to `c`, 1250ms after starting the connection to `b,` and 1500ms after starting the connection to `a`) `connect_timeout` is raised

This behavior aims to favor successful connections by allowing more time for each attempt, but it results in a timeout model that is difficult to reason about.

These methods have supported `resolv_timeout` and `connect_timeout` options even before the introduction of HEv2. However, in many use cases, it would be more convenient if a timeout occurred after a specified duration from the start of the method. Similar functions in other languages (such as PHP, Python, and Go) typically allow specifying only an overall timeout.

[Proposal]
I propose adding an `open_timeout` option to `Socket.tcp` in this PR, which triggers a timeout after a specified duration has elapsed from the start of the method.

The name `open_timeout` aligns with the existing accessor used in `Net::HTTP`.
If `open_timeout` is specified together with `resolv_timeout` and `connect_timeout`, I propose that only `open_timeout` be used and the others be ignored. While it is possible to support combinations of `open_timeout`, `resolv_timeout`, and `connect_timeout`, doing so would require defining which timeout takes precedence in which situations. In this case, I believe it is more valuable to keep the behavior simple and easy to understand, rather than supporting more complex use cases.

If this proposal is accepted, I also plan to extend `open_timeout` support to `TCPSocket.new`.

While the long-term future of `resolv_timeout` and `connect_timeout` may warrant further discussion, I believe the immediate priority is to offer a straightforward way to specify an overall timeout.

[Outcome]
If `open_timeout` is also supported by `TCPSocket.new`, users would be able to manage total connection timeouts directly in `Net::HTTP#connect` without relying on `Timeout.timeout`.
aa0f689bf4/lib/net/http.rb (L1657)

---

* Raise an exception if it is specified together with other timeout options

> If open_timeout is specified together with resolv_timeout and connect_timeout, I propose that only open_timeout be used and the others be ignored.

Since this approach may be unclear to users, I’ve decided to explicitly raise an `ArgumentError` if these options are specified together.

* Add doc

* Fix: open_timeout error should be raised even if there are still addresses that have not been tried
2025-06-14 09:54:34 +09:00
Jean Boussier
e22fc73c66 Fix a race condition in object_id for shareable objects
If an object is shareable and has no capacity left, it isn't
safe to store the object ID in fields as it requires an object
resize which can't be done unless all field reads are synchronized.

In this very specific case we create the object_id in advance,
before the object is made shareable.
2025-06-13 18:27:52 +02:00
Jean Boussier
97ea756e1c test/ruby/test_ractor.rb: avoid outputting anything 2025-06-13 17:13:13 +02:00
Nobuyoshi Nakada
2e7e78cd59
[Bug #21440] Stop caching member list in frozen Data/Struct class 2025-06-13 14:22:06 +09:00
Takashi Kokubun
7fa3e1a1db
ZJIT: Write a callee frame on JIT-to-JIT calls (#13579)
Co-authored-by: Max Bernstein <tekknolagi@gmail.com>
2025-06-12 17:18:50 -07:00
John Hawthorn
ef9301a6b7 Ensure crr->feature is an fstring 2025-06-12 13:13:55 -07:00
Ufuk Kayserilioglu
5ec9a392cd
[Bug #21439] Fix PM_SPLAT_NODE compilation error in for loops (#13597)
[Bug #21439] Fix PM_SPLAT_NODE compilation error in for loops

This commit fixes a crash that occurred when using splat nodes (*) as
the index variable in for loops. The error "Unexpected node type for
index in for node: PM_SPLAT_NODE" was thrown because the compiler
didn't know how to handle splat nodes in this context.

The fix allows code like `for *x in [[1,2], [3,4]]` to compile and
execute correctly, where the splat collects each sub-array.
2025-06-12 11:33:10 -04:00
Jean Boussier
a74c385208 Make setting and accessing class ivars lock-free
Now that class fields have been deletated to a T_IMEMO/class_fields
when we're in multi-ractor mode, we can read and write class instance
variable in an atomic way using Read-Copy-Update (RCU).

Note when in multi-ractor mode, we always use RCU. In theory
we don't need to, instead if we ensured the field is written
before the shape is updated it would be safe.

Benchmark:

```ruby
Warning[:experimental] = false

class Foo
  @foo = 1
  @bar = 2
  @baz = 3
  @egg = 4
  @spam = 5

  class << self
    attr_reader :foo, :bar, :baz, :egg, :spam
  end
end

ractors = 8.times.map do
  Ractor.new do
    1_000_000.times do
      Foo.bar + Foo.baz * Foo.egg - Foo.spam
    end
  end
end

if Ractor.method_defined?(:value)
  ractors.each(&:value)
else
  ractors.each(&:take)
end
```

This branch vs Ruby 3.4:

```bash
$ hyperfine -w 1 'ruby --disable-all ../test.rb' './miniruby ../test.rb'

Benchmark 1: ruby --disable-all ../test.rb
  Time (mean ± σ):      3.162 s ±  0.071 s    [User: 2.783 s, System: 10.809 s]
  Range (min … max):    3.093 s …  3.337 s    10 runs

Benchmark 2: ./miniruby ../test.rb
  Time (mean ± σ):     208.7 ms ±   4.6 ms    [User: 889.7 ms, System: 6.9 ms]
  Range (min … max):   202.8 ms … 222.0 ms    14 runs

Summary
  ./miniruby ../test.rb ran
   15.15 ± 0.47 times faster than ruby --disable-all ../test.rb
```
2025-06-12 14:55:13 +02:00
Jean Boussier
8b5ac5abf2 Fix class instance variable inside namespaces
Now that classes fields are delegated to an object with its own
shape_id, we no longer need to mark all classes as TOO_COMPLEX.
2025-06-12 13:43:29 +02:00
Hiroshi SHIBATA
166ff187bd [rubygems/rubygems] Removed ccache or sccache from args of Rust builder
```
 "  = note: some arguments are omitted. use `--verbose` to show all linker arguments\n" +
 "  = note: error: unexpected argument '-W' found\n" +
 "          \n" +
 "            tip: to pass '-W' as a value, use '-- -W'\n" +
 "          \n" +
 "          Usage: sccache [OPTIONS] <--dist-auth|--debug-preprocessor-cache|--dist-status|--show-stats|--show-adv-stats|--start-server|--stop-server|--zero-stats|--package-toolchain <EXE> <OUT>|CMD>\n" +
 "          \n" +
 "          For more information, try '--help'.\n" +
 "          \n" +
```

45e688ae62
2025-06-12 14:28:43 +09:00
Earlopain
970813d982 [ruby/prism] Fix parser translator during string escaping with invalid utf-8
Instead, prefer `scan_byte` over `get_byte` since that already returns the byte as an integer, sidestepping conversion issues.

Fixes https://github.com/ruby/prism/issues/3582

7f3008b2b5
2025-06-11 18:07:43 +00:00
Hiroshi SHIBATA
255e6e6197 Try to run ignored tests with macOS 15 2025-06-11 15:40:52 +09:00
Hiroshi SHIBATA
82e3312493 [ruby/net-http] Fixed test case for default content-type.
I changed content-type of request to "application/octet-stream" if request didn't have
content-type.

fc5870d2ac
2025-06-11 03:35:12 +00:00
David Rodríguez
dba72134de [rubygems/rubygems] Fix gem pristine sometimes not resetting extensions
If `gem pristine foo` is run, and there's a default copy of foo, only
executables for it are reset. However, that was causing other copies of
`foo` to only reset executables, which is unexpected.

We should not modify `options[:only_executables]`, but respect its value
for every gem, and make sure special handling for default gems does not
leak to other gems.

2c3039f1b0
2025-06-11 08:48:57 +09:00
David Rodríguez
6560083c39 [rubygems/rubygems] Normalize file existence helpers usage
a61cc97cd4
2025-06-11 08:48:57 +09:00
Samuel Giddins
7e3d271f76 [rubygems/rubygems] Install the best matching gem for the current platform in gem install
Instead of picking essentially a random matching platform

Signed-off-by: Samuel Giddins <segiddins@segiddins.me>

3727096297
2025-06-11 08:48:56 +09:00
John Hawthorn
c962735fe8 Add missing write barrier in set_i_initialize_copy
When we copy the table from one set to another we need to run write
barriers.
2025-06-09 10:06:47 -07:00