Adjust the specs to handle the backwards compatibility breakage.
While we will backport this to Ruby 4.0, to avoid temporary
breakage, leave Ruby 4.0 behavior unspecified until the fixes
are backported to it.
Co-authored-by: Jeremy Evans <code@jeremyevans.net>
Keyword tracking only needs membership, so replace identity hashes
with identity sets to avoid storing unused values. Add `rb_set_p`
for the type assertion in `vm_check_keyword`.
Add benchmarks for 31, 32 and 128 keyword parameters with sparse and
dense dynamic defaults, using both direct keywords and keyword splats.
The 31-parameter cases provide a bitmask-only control.
Local arm64 macOS measurements show about 16-26% higher throughput
with many omitted dynamic defaults at 32 and 128 parameters. Smaller
differences remain noisy, including in the bitmask-only controls.
The tracking container is created at call time, leaving IBF and
`ISeq#to_a` unchanged. Verify IBF-loaded calls with the Integer
refinement and colliding keyword indices from [Bug #22335].
This commit changes Array#& to use a temporary Set instead of Hash for
performance and memory savings. We can see in the following benchmark:
a = (0...10_000).to_a
b = (5_000...15_000).to_a
1_000.times { a & b }
Results:
Benchmark 1: master
Time (mean ± σ): 196.4 ms ± 9.1 ms [User: 182.9 ms, System: 9.5 ms]
Range (min … max): 186.3 ms … 214.7 ms 13 runs
Benchmark 2: branch
Time (mean ± σ): 163.4 ms ± 3.3 ms [User: 152.7 ms, System: 7.8 ms]
Range (min … max): 157.7 ms … 169.9 ms 17 runs
Summary
branch ran
1.20 ± 0.06 times faster than master
This commit changes Array#| to use a temporary Set instead of Hash for
performance and memory savings. We can see in the following benchmark:
a = (0...10_000).to_a
b = (5_000...15_000).to_a
1_000.times { a | b }
Results:
Benchmark 1: master
Time (mean ± σ): 237.5 ms ± 2.0 ms [User: 223.4 ms, System: 10.9 ms]
Range (min … max): 234.6 ms … 240.7 ms 12 runs
Benchmark 2: branch
Time (mean ± σ): 165.2 ms ± 3.8 ms [User: 151.2 ms, System: 10.8 ms]
Range (min … max): 159.8 ms … 174.2 ms 18 runs
Summary
branch ran
1.44 ± 0.04 times faster than master
This is designed to replace rb_ident_hash_new calls when such hashes
are used purely with with true values.
To implement this, add a set_alloc_with_size_and_type static function,
and have set_alloc_with_size and rb_ident_set_new call it.
This changes the following methods to compact the set after removal:
* `^`
* `-`
* `difference`
* `subtract`
* `keep_if`
* `select!`
* `filter!`
Fixes [#22210]
The Range Marshal compat dumper would allocate
an Object with no size information, hence get a 32B slot
with enough space for 2 ivars, then insert 3 ivars causing
it to spill.
This isn't a big problem, but somewhat shows that the interface
isn't WVA aware.
By introducing `rb_class_allocate_instance_capa` we can directly
allocate an object with enough room.
Set#include? built its receiver from an Array literal, so the
`hash`/`eql?` semantics the surrounding text describes did not apply.
Set#each wrote `sum => 6`, which is a rightward-assignment pattern
match rather than an output comment.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>