1182 Commits
Author SHA1 Message Date
Burdette Lamar b17040e2e5 [DOC] Tweaks for ENV#fetch_values (#19390) 2026-10-19 08:32:14 +09:00
John Hawthorn 25fb329ec9 Add missing write barriers to hash_copy's ST to AR path
ar_add_direct_i, added in 60a4894bdb (Dynamic ar_table size), inserts the
entries with ar_insert_direct and no write barrier. Unlike the other
hash_copy paths it can run Ruby code (ar_insert_direct may call #eql?) and
so trigger a GC part way through the copy. The new hash is then already
known to the GC with only the entries added so far, and the rest are never
barriered.

Found with wbcheck (WBCHECK_VERIFY_AFTER_WB=1) as an intermittent failure of
TestCoverage#test_branch_coverage_for_safe_method_invocation.
2026-10-16 14:04:59 -07:00
Hiroshi SHIBATAandClaude Opus 5.5 c9dd247de0 Use rb_len_t in the bulk Hash builders and the ZJIT helpers
The ZJIT bindings are regenerated with make zjit-bindgen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 16:45:25 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 ee3d6c987b Use rb_len_t for the lengths and indices left in long
These still held String and Array lengths and indices in long, or cast them to long. rb_len_t is still long everywhere, so the generated code does not change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 16:45:25 +09:00
Hiroshi SHIBATAandClaude Opus 5 77f04f52ee Use rb_len_t for lengths in hash.c, st.c and set.c
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-09 14:00:15 +09:00
Hiroshi SHIBATAandClaude Opus 5 cc3ba11012 Use rb_len_t in the C API for lengths and indices
Once rb_len_t widens this changes the `long *` output parameters of rb_range_beg_len(), rb_str_subpos(), rb_arithmetic_sequence_beg_len_step(), ruby_enc_find_basename() and ruby_enc_find_extname(), so extensions passing `long *` to them will need to be updated. The extension guides list these signatures verbatim and follow along.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-09 14:00:15 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 0fef975dce Remove Solaris 9 and earlier support
Extended Support for Solaris 9 ended in 2014. Solaris 10 and later have setenv and unsetenv, and libumem is always available, so the version specific fallbacks are no longer needed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 09:00:26 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 2884fbde08 Assume unsetenv returns int
POSIX.1-2001 made unsetenv return int. The platforms that still declared it void, such as Mac OS X 10.4, FreeBSD 6 and glibc before 2.2.2, are no longer supported.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 09:00:26 +09:00
Jean Boussier 5c128f545b Deprecate RHASH_TBL
[Feature #22232]

Guaranteeing that any hash can be converted into an st_table is
limiting the evolution of RHash.

None of the public usages of `RHASH_TBL` were justified, they all
had equivalent `rb_hash_*` public APIs to perform the same thing
more efficiently without disabling write barriers nor coercing the
hash into an st_table.
2026-09-30 11:51:14 +02:00
Hiroshi SHIBATAandClaude Opus 5.5 224bb40844 Remove Windows redefinitions that duplicate win32.h
include/ruby/win32.h already maps stat, lstat, access, truncate, utimensat, unlink, rename and getenv to the same rb_w32_* functions when compiling the core with RUBY_EXPORT.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 06:05:59 +09:00
Jean Boussier 5a395d2ad6 marshal.c: embed compat_tbl in load and dump args 2026-09-24 13:31:56 +02:00
John Hawthorn 73055acd57 Forbid setting ivars on Ractor shareable objects
Previously we had a check that objects which were shareable, but not
frozen on a non-main Ractor would raise an exception if instance
variables were read. This prevented a non-main Ractor reading
non-shareable objects.

This changes the behaviour to forbid all writes to shareable objects
(even when unfrozen). This is done by re-purposing the frozen flag on
the object shape to reflect (FL_FROZEN || FL_SHAREABLE).

With IV writes forbidden on all shareable objects whether or not they
are frozen (with the exception of classes and modules), we can also
remove the check against reading instance variables, since no unsafe
instance variables can be set.

[Bug #22291]
2026-09-16 12:26:11 -07:00
Hiroshi SHIBATAandClaude Opus 5 fb02f6ead2 hash.c: Guard the uninitialized st_table scrub with #if RUBY_DEBUG
`assert.h` always defines `RUBY_DEBUG`, as either 0 or 1, so `#ifdef` was always true and release builds paid for the two stores as well. They exist only so that the `RUBY_ASSERT` in `st_replace` and in `hash_copy` can tell an uninitialized table apart, and those compile away when `RUBY_DEBUG` is 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 12:52:31 +09:00
Peter Zhu 98d4482408 Fix uninitialized hash ar_entry hint
The ar_entry hint may be initialized when it is used. It is caught by
Valgrind:

    ==91514== Conditional jump or move depends on uninitialised value(s)
    ==91514==    at 0x1C5369: ar_find_entry_hint (hash.c:674)
    ==91514==    by 0x1C85A5: ar_find_entry (hash.c:718)
    ==91514==    by 0x1C85A5: ar_insert_direct.isra.0 (hash.c:1086)
    ==91514==    by 0x1D24BE: ar_insert (hash.c:1114)
    ==91514==    by 0x1D24BE: ar_bulk_insert (hash.c:5377)
    ==91514==    by 0x1D24BE: rb_hash_bulk_insert.part.0 (hash.c:5392)
    ==91514==    by 0x694891: pm_compile_hash_elements (prism_compile.c:1569)
    ==91514==    by 0x69BBAB: pm_setup_args_core.isra.0 (prism_compile.c:1755)
    ==91514==    by 0x69C682: pm_setup_args.constprop.0 (prism_compile.c:2146)
    ==91514==    by 0x69F707: pm_compile_call (prism_compile.c:3821)
    ==91514==    by 0x68906D: pm_compile_call_node (prism_compile.c:7527)
    ==91514==    by 0x68AB4B: pm_compile_node (prism_compile.c:8893)
    ==91514==    by 0x68CF71: pm_compile_node (prism_compile.c:10445)
    ==91514==    by 0x6A8462: pm_compile_scope_node (prism_compile.c:7114)
    ==91514==    by 0x68BB32: pm_compile_node (prism_compile.c:10306)
    ==91514==    by 0x6A99F4: pm_iseq_compile_node (prism_compile.c:10627)
    ==91514==    by 0x20C1DA: pm_iseq_build (iseq.c:1236)
    ==91514==    by 0x689DCB: pm_new_child_iseq (prism_compile.c:1367)
    ==91514==    by 0x689DCB: pm_compile_node (prism_compile.c:9173)
    ==91514==    by 0x68CF49: pm_compile_node (prism_compile.c:10443)
    ==91514==    by 0x6A7D2D: pm_compile_scope_node (prism_compile.c:7152)
    ==91514==    by 0x68BB32: pm_compile_node (prism_compile.c:10306)
    ==91514==    by 0x6A99F4: pm_iseq_compile_node (prism_compile.c:10627)
    ==91514==    by 0x20C1DA: pm_iseq_build (iseq.c:1236)
    ==91514==    by 0x68CB0C: pm_new_child_iseq (prism_compile.c:1367)
    ==91514==    by 0x68CB0C: pm_compile_node (prism_compile.c:9972)
    ==91514==    by 0x68CF49: pm_compile_node (prism_compile.c:10443)
    ==91514==    by 0x6A7D2D: pm_compile_scope_node (prism_compile.c:7152)
    ==91514==    by 0x68BB32: pm_compile_node (prism_compile.c:10306)
    ==91514==    by 0x6A9A77: pm_iseq_compile_node (prism_compile.c:10617)
    ==91514==    by 0x20C1DA: pm_iseq_build (iseq.c:1236)
    ==91514==    by 0x20C3B3: pm_iseq_new_with_opt_try (iseq.c:1256)
    ==91514==    by 0x18B336: rb_protect (eval.c:1154)
    ==91514==    by 0x20A9D4: pm_iseq_new_with_opt (iseq.c:1284)
    ==91514==    by 0x20A9D4: pm_iseq_new_top (iseq.c:1076)
    ==91514==    by 0x212227: load_prism_parse (load.c:756)
    ==91514==    by 0x18B513: rb_ec_ensure (eval.c:1176)
    ==91514==    by 0x21524D: load_iseq_eval (load.c:799)
    ==91514==    by 0x21524D: require_internal (load.c:1403)
    ==91514==    by 0x2153C8: rb_require_string_internal (load.c:1513)
    ==91514==    by 0x2153C8: rb_require_string (load.c:1499)
    ==91514==    by 0x2153C8: rb_f_require (load.c:1089)
    ==91514==    by 0x38E196: vm_call_cfunc_with_frame_ (vm_insnhelper.c:3904)
    ==91514==    by 0x395851: vm_call_symbol (vm_insnhelper.c:4403)
    ==91514==    by 0x3A2C68: vm_sendish (vm_insnhelper.c:6283)
    ==91514==    by 0x3A2C68: vm_exec_core (insns.def:912)
    ==91514==    by 0x3929C9: rb_vm_exec (vm.c:2885)
    ==91514==    by 0x214B88: load_iseq_eval (load.c:827)
    ==91514==    by 0x214B88: require_internal (load.c:1403)
    ==91514==    by 0x2153C8: rb_require_string_internal (load.c:1513)
    ==91514==    by 0x2153C8: rb_require_string (load.c:1499)
    ==91514==    by 0x2153C8: rb_f_require (load.c:1089)
    ==91514==    by 0x38E196: vm_call_cfunc_with_frame_ (vm_insnhelper.c:3904)
    ==91514==    by 0x395851: vm_call_symbol (vm_insnhelper.c:4403)
    ==91514==    by 0x3A2C68: vm_sendish (vm_insnhelper.c:6283)
    ==91514==    by 0x3A2C68: vm_exec_core (insns.def:912)
    ==91514==    by 0x3929C9: rb_vm_exec (vm.c:2885)
    ==91514==    by 0x214B88: load_iseq_eval (load.c:827)
    ==91514==    by 0x214B88: require_internal (load.c:1403)
    ==91514==    by 0x2153C8: rb_require_string_internal (load.c:1513)
    ==91514==    by 0x2153C8: rb_require_string (load.c:1499)
    ==91514==    by 0x2153C8: rb_f_require (load.c:1089)
    ==91514==    by 0x38E196: vm_call_cfunc_with_frame_ (vm_insnhelper.c:3904)
    ==91514==    by 0x395500: vm_call_alias (vm_insnhelper.c:4297)
    ==91514==    by 0x3A2C68: vm_sendish (vm_insnhelper.c:6283)
    ==91514==    by 0x3A2C68: vm_exec_core (insns.def:912)
    ==91514==    by 0x3929C9: rb_vm_exec (vm.c:2885)
    ==91514==    by 0x397967: vm_yield_with_cref (vm.c:1950)
    ==91514==    by 0x397967: vm_yield (vm.c:1958)
    ==91514==    by 0x397967: rb_ec_yield (vm_eval.c:1395)
    ==91514==    by 0x60D03E: rb_ary_each (array.c:2792)
    ==91514==    by 0x38E196: vm_call_cfunc_with_frame_ (vm_insnhelper.c:3904)
    ==91514==    by 0x3A3178: vm_sendish (vm_insnhelper.c:6283)
    ==91514==    by 0x3A3178: vm_exec_core (insns.def:864)
    ==91514==    by 0x392F22: vm_exec_loop (vm.c:2912)
    ==91514==    by 0x392F22: rb_vm_exec (vm.c:2891)
    ==91514==    by 0x397967: vm_yield_with_cref (vm.c:1950)
    ==91514==    by 0x397967: vm_yield (vm.c:1958)
    ==91514==    by 0x397967: rb_ec_yield (vm_eval.c:1395)
    ==91514==    by 0x60D03E: rb_ary_each (array.c:2792)
    ==91514==    by 0x38E196: vm_call_cfunc_with_frame_ (vm_insnhelper.c:3904)
    ==91514==    by 0x3A3178: vm_sendish (vm_insnhelper.c:6283)
    ==91514==    by 0x3A3178: vm_exec_core (insns.def:864)
    ==91514==    by 0x392F22: vm_exec_loop (vm.c:2912)
    ==91514==    by 0x392F22: rb_vm_exec (vm.c:2891)
    ==91514==    by 0x1874F2: rb_ec_exec_node (eval.c:299)
    ==91514==    by 0x18A208: ruby_run_node (eval.c:337)
    ==91514==    by 0x184525: rb_main (main.c:42)
    ==91514==    by 0x184525: main (main.c:62)
2026-09-16 09:38:50 +09:00
Nobuyoshi Nakada 04c503bc16 Explicitly cast to unsigned long to fix the sign-compare warning 2026-08-31 09:54:35 +09:00
Mrmaxmeier 69b49ac7ae hash.c: avoid signed integer overflow in ar_hint_first_match SWAR splat
This was previously flagged by ubsan because the AR_HINT_BASE_MASK
constant is implicitly typed as long:

hash.c:664:43: runtime error: signed integer overflow: 72340172838076673
* 131 cannot be represented in type 'long'

Notably, in an unsigned context, this line can't overflow
(AR_HINT_BASE_MASK is 0x0101..0101). VALUE is always an unsigned type.
2026-08-28 09:43:16 +02:00
Jean Boussier 127e903860 hash.c: add a substition hint
By guaranteeing that hints can't match `RHASH_AR_CLEARED_HINT`
we can save on checking the key for `UNDEF_P` in a bunch of places.
2026-08-27 12:04:48 +02:00
Nobuyoshi Nakada 9ee713a92c Revert "Adjust indent [ci skip]"
This reverts commit c0a526dd97.
2026-08-27 09:27:53 +09:00
Nobuyoshi Nakada c0a526dd97 Adjust indent [ci skip] 2026-08-27 09:26:49 +09:00
Peter Zhu 0b2edb5b9a Implement support for AR table backed identity hashes
This commit adds support for using AR tables for identity hashes (hashes
created by method Hash#compare_by_identity). Before this change, identity
hashes always used ST tables. However, this used a lot more memory because
ST tables are quite large. This commit adds a new flag RHASH_COMPARE_BY_IDENTITY
for AR tables that are compare-by-identity.

For example, for an empty identity hash, the size goes from 256 bytes to
160 bytes:

    require "objspace"

    h = {}.compare_by_identity
    puts ObjectSpace.memsize_of(h)
2026-08-26 21:04:27 +09:00
Jean Boussier 76edf35f9c Refactor RHash size computations
Share the same code between gc.c and hash.c.
2026-08-26 10:41:20 +02:00
Jean Boussier 89699e814e hash.c: memzero hashes before allocating st_table
`hash_copy` will call `st_init_existing_table_with_size` which
allocates and may trigger GC causing the current hash to be marked.

So we need to zero-out the `st_table` to avoid a segfault.
2026-08-25 17:54:02 +02:00
Jean Boussier 759cfbb903 Hash#merge guess size 2026-08-25 15:24:55 +02:00
Jean Boussier 60a4894bdb Dynamic ar_table size
Instead of always allocating `ar_table` backed hashes in 160B
slots for them to have capacity of `RHASH_AR_TABLE_MAX_SIZE` (`8`),
they can now be allocated in any slot size between `64B` and `160B`.

`64B` is the minimum slot size that still allows transitioning to
an `st_table` if necessary.

The assumption is that there is a large number of literal hashes
and keyword argument hashes being built, and the overwhelming majority
of them aren't appended to.

When this assumption hold, this patch saves memory and reduce GC
pressure by allocating in a smaller slot than before.

However when the assumption doesn't hold, it has the oppositve effect
as the Hash will transition to an `st_table` when before it may have
stayed an `ar_table`.

Currently the main blocked for this change is that the compiler
has a tendency to generate code that make the final Hash size unknown.

For instance: `{a: 4, b: 4 + 1}` is compiled as:

```
0000 duphash                                {a: 4}                    (   1)[Li]
0002 putspecialobject                       1
0004 swap
0005 putobject                              :b
0007 putobject                              4
0009 putobject_INT2FIX_1_
0010 opt_plus                               <calldata!mid:+, argc:1, ARGS_SIMPLE>[CcCr]
0012 opt_send_without_block                 <calldata!mid:core#hash_merge_ptr, argc:3, ARGS_SIMPLE>
```

Here `duphash` has no information about how large of a hash it needs to allocate.
For this patch to be more efficient the compiler should generate something like:

```
0000 putobject                              {a: 4}                    (   1)[Li]
0002 putspecialobject                       1
0004 swap
0005 putobject                              :b
0007 putobject                              4
0009 putobject_INT2FIX_1_
0010 opt_plus                               <calldata!mid:+, argc:1, ARGS_SIMPLE>[CcCr]
0012 opt_send_without_block                 <calldata!mid:core#hash_merge_ptr, argc:3, ARGS_SIMPLE>
```

So that it's `hash_merge_ptr` that is responsible for allocating the final hash,
given it does have a much better clue of how large it would need to be.

Demo:

```ruby
require 'objspace'
def size(hash)
  puts "size: #{hash.size}\tmemsize: #{ObjectSpace.memsize_of(hash)}"
end

size({})
size(a:1)
size(a:1, b:2)
size(a:1, b:2, c:3)
size(a:1, b:2, c:3, d:4)
size(a:1, b:2, c:3, d:4, e:5)
size(a:1, b:2, c:3, d:4, e:5, f:6)
size(a:1, b:2, c:3, d:4, e:5, f:6, g:7)
size(a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8)
size(a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9)
```

Before:

```
size: 0	memsize: 160
size: 1	memsize: 160
size: 2	memsize: 160
size: 3	memsize: 160
size: 4	memsize: 160
size: 5	memsize: 160
size: 6	memsize: 160
size: 7	memsize: 160
size: 8	memsize: 160
size: 9	memsize: 464
```

After:

```
size: 0	memsize: 64
size: 1	memsize: 64
size: 2	memsize: 64
size: 3	memsize: 80
size: 4	memsize: 96
size: 5	memsize: 128
size: 6	memsize: 128
size: 7	memsize: 160
size: 8	memsize: 160
size: 9	memsize: 448
```
2026-08-25 15:24:55 +02:00
Jean Boussier 6d4a6a939f Parametize RHASH_AR_TABLE_MAX_BOUND
For now it still returns a constant, but clarify when we're looking
for the max bound, versus a miss, etc.
2026-08-25 15:24:55 +02:00
Nobuyoshi Nakada f21a04fe83 Fix maybe-uninitialized warning
With gcc 15.2.0 on aarch64 Ubuntu 26.4:

```console
hash.c: In function ‘rb_hash_s_create’:
hash.c:1982:20: warning: ‘hash’ may be used uninitialized [-Wmaybe-uninitialized]
 1982 |             return hash;
      |                    ^~~~
hash.c:1920:11: note: ‘hash’ was declared here
 1920 |     VALUE hash, tmp;
      |           ^~~~
```
2026-08-25 22:15:27 +09:00
Jean Boussier 457029612f Inverse hash_alloc and hash_alloc_capa naming 2026-08-25 00:21:58 +02:00
Jean Boussier c7018a38c2 Hash#rehash: right-size the temporary ar_table 2026-08-25 00:21:58 +02:00
Jean Boussier 2449a13a4f Hash::[] start from a right-sized hash
Saves on potentially having to reallocate multiple times.
2026-08-24 14:10:53 +02:00
Jean Boussier f01bf185f6 Refactor core_hash_merge_ptr and core_hash_merge_kw
Rather than start from a mutable hash created with `newhash` or
`duphash`, and then iteratively insert into it, it's preferable to
start from a constant hidden hash, so that we can directly allocate
the final hash with the right size.

For instance:

```ruby
{a: 1, B => 2, c: 3}
```

Before:

```
0000 duphash                                {a: 1}                    (   1)[Li]
0002 putspecialobject                       1
0004 swap
0005 opt_getconstant_path                   <ic:0 B>
0007 putobject                              2
0009 putobject                              :c
0011 putobject                              3
0013 opt_send_without_block                 <calldata!mid:core#hash_merge_ptr, argc:5, ARGS_SIMPLE>
```

After:

```
0000 putobject                              {a: 1}                    (   1)[Li]
0002 putspecialobject                       1
0004 swap
0005 opt_getconstant_path                   <ic:0 B>
0007 putobject                              2
0009 putobject                              :c
0011 putobject                              3
0013 opt_send_without_block                 <calldata!mid:core#hash_merge_ptr, argc:5, ARGS_SIMPLE>
```

Since, `duphash` has no idea how large the final hash might be,
it can't right-size the hash it allocates.

Hence it's preferable to use a `putobject` and let `hash_merge_ptr`
compute the final hash right size by assuming all keys are unique.
2026-08-24 09:12:31 +02:00
Jean Boussier 93a521bf3a hash.c: split allocation and st_init
`st_replace` assumes that the `st_table` hasn't been
initialized, so when duping a hash, we shouldn't pre-allocate
the `st_table` otherwise we'll leak memory.
2026-08-23 15:26:22 +02:00
Jean Boussier 56abc30ec2 Righ-size more hashes
The pattern of allocating an empty hash with `rb_hash_new()` and
then appending to it is relatively wasteful, because every time
we go over the hash capacity, we'll have to `realloc`, rehash etc.

It may even get worse if https://github.com/ruby/ruby/pull/18345
lands, as right now an empty hash starts with a capacity of 8,
but it may very well start with a capacity of 2.

Hence in cases where the final hash size is easy to predict, we
should use `rb_hash_new_capa()`.
2026-08-23 11:50:40 +02:00
Jean Boussier fb99639ed9 Get rid of rb_hash_new_with_size
It's redundant with `rb_hash_new_capa` which is public API,
might as well use that one.
2026-08-16 13:50:22 +02:00
Jean Boussier d1c079751b hash.c: refactor allocator
Centralize the slot size logic in `hash_alloc_capa`.
2026-08-15 09:21:53 +02:00
Jean Boussier 1b0c22c115 hash.c: compact ar_table on freeze
Since frozen ar_table can occupy smaller slots,
shrinking the table on freeze potentially allow the
Hash to be demoted to an even smaller slot.
2026-08-14 23:00:13 +02:00
Jean Boussier 7da70f1773 hash.c: speedup ar_find_entry_hint with SWAR
Instead of iterating over the bytes of the ar_table hints
one by one, we can use a little bit of SWAR code to match them
all at once and return the first matching byte index.

In theory we could even re-use the mask to extract all matching
position, however we can't do that because since `ar_equal` calls
back into Ruby, the hints may change after every iteration.

```
compare-ruby: ruby 4.1.0dev (2026-08-06T14:05:57Z master 9658933451) +YJIT +PRISM [arm64-darwin25]
built-ruby: ruby 4.1.0dev (2026-08-06T16:42:50Z ar-find-entry-swar-2 723ff01514) +YJIT +PRISM [arm64-darwin25]
```

|            |compare-ruby|built-ruby|
|:-----------|-----------:|---------:|
|hit_first   |     13.891M|   15.085M|
|            |           -|     1.09x|
|hit_third   |     13.322M|   15.065M|
|            |           -|     1.13x|
|hit_fourth  |     12.759M|   14.410M|
|            |           -|     1.13x|
|hit_last    |     11.545M|   15.275M|
|            |           -|     1.32x|
|miss        |     10.872M|   16.286M|
|            |           -|     1.50x|
2026-08-14 11:45:14 +02:00
Peter Zhu 1c657aefdc ZJIT: GC fastpath for HashDup
Implements GC fastpath for HashDup instruction for AR hashes (<= 8 elements).
This instruction is used for non-empty hashes that have only compile-time
constants.

Benchmark:

    def run(times)
      i = 0
      while i < times
        a = {a: 1, b: 2, c: 3}
        i += 1
      end
    end

    30.times { run(1) }
    run(10_000_000)

Results:

    Benchmark 1: master
      Time (mean ± σ):     145.2 ms ±   2.8 ms    [User: 136.9 ms, System: 6.6 ms]
      Range (min … max):   141.1 ms … 152.3 ms    20 runs

    Benchmark 2: branch
      Time (mean ± σ):      82.1 ms ±   1.4 ms    [User: 74.6 ms, System: 6.0 ms]
      Range (min … max):    80.1 ms …  86.9 ms    35 runs

    Summary
      branch ran
        1.77 ± 0.05 times faster than master
2026-08-14 10:15:56 +09:00
Peter Zhu f336732287 ZJIT: Centralize shape setting for ZJIT GC fastpath
This commit centralizes shape setting for objects in the ZJIT GC fastpath
into the rb_zjit_new_obj_shape function to avoid each type having to deal
with shapes individually.
2026-08-07 16:31:14 -04:00
Jean Boussier 66c00fd536 rb_hash_init: don't spill to st_table unless needed
Up to `RHASH_AR_TABLE_MAX_SIZE` there's no need to initialize
an `st_table`.
2026-08-06 12:57:06 +02:00
Jean Boussier 5b505f860b Reduce RHASH_TBL_RAW usage 2026-08-06 12:41:07 +02:00
Shugo Maeda 1d9b1291dc [DOC] Deprecate ruby2_keywords
Add documentation-only deprecation notices to Module#ruby2_keywords,
main.ruby2_keywords, Proc#ruby2_keywords, Hash.ruby2_keywords_hash?,
and Hash.ruby2_keywords_hash, as the first phase of the schedule
proposed at https://bugs.ruby-lang.org/issues/22205.
2026-08-06 16:31:41 +09:00
Luke Gruber 70874cc592 ZJIT: fix gen_new_hash to use proper shape_id in flags
If the shape capacity isn't set on an object, one thing that fails is
moving it across Ractors. The new object created in the dst Ractor needs
to be big enough to embed the contents if the src was embedded.
2026-08-05 12:49:38 -04:00
Ajay Krishnan 5968753774 [DOC] Fix ENV.reject block result description (#17936) 2026-07-26 11:11:23 -04:00
Ajay Krishnan 70fa08003f [DOC] Fix ENV block argument descriptions 2026-07-26 11:03:07 -04:00
Peter Zhu 08fb9346de Don't double set ar_hint in ar_copy 2026-07-24 14:02:27 -04:00
YO4 239a472609 fix ENV.keys encoding on windows
Fix the encoding of ENV.keys elements to UTF-8 on windows.
They contain UTF-8 byte sequences with locale encoding.
2026-07-24 17:31:45 +09:00
Hiroshi SHIBATAandClaude Opus 4.8 f636ac3825 Fix broken RDoc examples that raise or fail to run
The Hash#[] and Array#product examples referenced undefined variables,
the StringIO doc named a nonexistent File::RDRW constant, and
Pathname#mkpath's call-seq advertised a positional permissions
argument that the keyword-only implementation does not accept.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 15:19:19 +09:00
Matt Valentine-House ff8e913048 Inline RHash ifnone offset into jit_bindgen_constants 2026-07-08 23:20:00 +01:00
Matt Valentine-House 841ea9d502 Inline GC fastpath in ZJIT for newhash instruction
This extends the ZJIT GC fast path to the newhash instruction for empty
hashes.

This was verified in a stripped down benchmarking environment, using the
following micro-benchmark in ruby-bench:

```
def run(max)
  i = 0
  while i < max
    h = {}
    i += 1
  end
end

require_relative '../harness/loader.rb'

run_benchmark(50) do
  50.times do
    run(500_000)
  end
end
```

This patch resulted in a ~30% speedup.

```
master: ruby 4.1.0dev (2026-07-07T14:04:07Z master c51b1596c0) +ZJIT +PRISM [x86_64-linux]
experiment: ruby 4.1.0dev (2026-07-07T19:27:04Z mvh-zjit-inline-fa.. 60730f1aa1) +ZJIT +PRISM [x86_64-linux]

-----  ------------  ---------------  ------------------  -----------------
bench   master (ms)  experiment (ms)  experiment 1st itr  master/experiment
hash   682.3 ± 0.7%     518.0 ± 1.0%               1.082              1.317
-----  ------------  ---------------  ------------------  -----------------

Legend:
- experiment 1st itr: ratio of master/experiment time for the first benchmarking iteration.
- master/experiment: ratio of master/experiment time. Higher is better for experiment. Above 1 represents a speedup.
```
2026-07-08 23:20:00 +01:00
Koichi Sasada 8e6fd8fed4 fix control flow
`do { ...; continue; } while(0)` doesn't retry the loop body.

pointed out by Coverity Scan and mame.
2026-07-02 05:19:03 +09:00