Commit Graph
1329 Commits
Author SHA1 Message Date
Luke Gruber 33adbcae3a ZJIT: enable alloc fastpath when compiled with --enable-zjit=dev
This also enables the alloc fastpath where it previously wasn't enabled
when `-DRUBY_DEBUG` is set in cflags during compilation. This will allow
us to test the ZJIT alloc fastpath in CI and when running ZJIT tests
locally in dev (--enable-zjit=dev) or debug mode (cflags="-DRUBY_DEBUG=1").
2026-08-07 18:10:28 -04: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
Koichi SasadaandClaude Opus 5 4cd8f755cc Ractor: keep the elements a moved array still shares
The array counterpart of f4e50b9993.  A frozen array is handed out as a shared
root as it is, without the shared root flag (ary_make_shared), so a subseq or a
dup of an embedded one reads the elements straight out of its slot:

    ary = Array.new(40) { |i| i + 1 }
    ary.instance_variable_set(:@iv, [])   # unshareable, so it is moved
    ary.freeze
    sharer = ary[1, 38]                    # reads ary's elements in place
    r.send(ary, move: true)
    sharer                                 #=> [false, false, ...]

Two things go wrong once the root is hollowed out.  The wipe added by 556296cbe0
zeroes the slot the sharer is reading, which is the visible breakage above; skip
it for an embedded shared root, as the string side already does.

The other one predates the wipe.  Arrays let a shared root move and re-point the
sharer in gc_ref_update_array(), which needs to know that the payload lives in
the root's slot -- and a Ractor::MovedObject no longer says so, so the sharer was
left pointing into the old slot.  Pin such a root instead, the way strings have
handled embedded roots since 80ea7fbad8.

Reachable since arrays moved to variable width allocation (a51f30c671): before
that an embedded array was at most 3 elements, and ary_make_partial copies rather
than shares at that size, so an embedded array was never a shared root.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 13:21:53 +09:00
John Hawthorn 3ab7644a89 Add writebarrier for Array#reverse 2026-07-28 10:47:48 -07:00
Nobuyoshi Nakada 1b560fae2a Revert [Feature #17056] offset specs for Array#index and rindex"
This reverts commits:

* fa055b6d8b
  Allow specifying the position to start search from in Array#index
  and Array#rindex

* 33db313e85.
  Add offset specs for `Array#index` and `rindex`
2026-07-25 17:16:11 +09:00
fatkodima fa055b6d8b Allow specifying the position to start search from in Array#index and Array#rindex 2026-07-25 13:27:24 +09:00
Takashi Kokubun 37a852bdf5 ZJIT: Rename rb_jit_* functions to rb_builtin_* (#18039)
Rename rb_jit_* functions to rb_builtin_*
2026-07-23 15:32:57 -04:00
Peter Zhu a1066005bd Make rb_jit_ary_push static 2026-07-22 13:20:49 -04:00
Luke Gruber 1aebcb61d0 ZJIT: duparray allocation fastpath for arrays we embed
We can reuse some of this work for gen_new_array fastpath for
embedded arrays.
2026-07-16 22:32:15 -04: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
Peter Zhu 79da507032 Prevent overflow of length bits for embedded arrays
Embedded arrays only use 7 bits for the length, so it will overflow if
the GC can allocate large slots. We need to add the cap to ary_embeddable_p.
2026-07-10 15:35:52 +09:00
Nobuyoshi Nakada ee09d07d54 pack.c: Expand the result array in advance
Expand the room for all items at once before unpacking them, instead
of extending it one by one.
2026-07-08 21:25:45 +09:00
Jean Boussier 3d350d6670 Use rb_obj_shape_slot_size over rb_gc_obj_slot_size
`rb_gc_obj_slot_size` has to check the page metadata to
get the slot size, which likely cause cache misses.

`rb_obj_shape_slot_size` does simple arithmetic using
only a few shape bits.

```
compare-ruby: ruby 4.1.0dev (2026-07-08T03:48:16Z master 01c5b2e890) +PRISM [arm64-darwin25]
built-ruby: ruby 4.1.0dev (2026-07-08T10:17:41Z gc-changed-slot-size 08029b0f7c) +PRISM [arm64-darwin25]
warming up.
```

|                        |compare-ruby|built-ruby|
|:-----------------------|-----------:|---------:|
|binary_concat_embedded  |      5.262M|    5.707M|
|                        |           -|     1.08x|
2026-07-08 13:39:59 +02:00
Jean Boussier dac89892b9 gc: call rb_gc_obj_changed_slot_size for all types
Now that the shape contains the slot capacity, we should update
the shape for all objects when moving them, not just T_OBJECT.
2026-07-08 13:39:59 +02:00
Jean Boussier 263f06ad49 RBASIC_SET_SHAPE_ID: also strip the layout bits
Like the capacity part, the layout part of an object shape
almost never changes. The few exceptions are:

  - On allocation.
  - On being compacted by GC.
  - When RObject oberflows.

As such it simplifies a lot of code if `RBASIC_SET_SHAPE_ID` strips
the layout bits, as we often copy the shape from IMEMO/fields to
the owner object and vice-versa.

Also change `RBASIC_SET_SHAPE_ID_WITH_CAPACITY` into
`RBASIC_SET_FULL_SHAPE_ID` so it can be used for assigning both
capacity and layout.
2026-07-07 13:12:35 +02:00
Nobuyoshi Nakada e021de15af Trivial refactor around rb_ary_subseq_step
Check for `step` before the length, although it looks impossible to
create 0-step `ArithmeticSequence` currently.
2026-07-02 12:43:57 +09:00
Peter Zhu 15b8aafa96 Make rb_ary_subseq_step static 2026-06-26 08:32:19 -04:00
John HawthornandLuke Gruber daffaaee73 Mark most TypedData types as THREAD_SAFE_FREE
Set RUBY_TYPED_THREAD_SAFE_FREE on TypedData types whose dfree function
is trivially safe, and only frees its own memory

Types not yet marked as THREAD_SAFE_FREE:
- id2ref_tbl_type: sets the process-global id2ref_tbl to NULL.
- mutex_data_type: unlinks itself from another thread's keeping_mutexes list.
- autoload_data_type: deletes nodes from a shared intrusive list.
- autoload_const_type: deletes itself from a shared list.
- rb_cont_data_type: mutates the shared fiber pool and the global first_jit_cont list.
- rb_fiber_data_type: delegates to cont_free.
- FiberPoolDataType: mutates shared fiber pool free-lists.
- ractor_data_type: reconfigures global VM event-hook flags and call caches.
- exported_object_registry: frees a global table under the VM lock.
- rb_box_data_type (Box::Entry): unlinks classext from other live class and module objects.
- box_ext_cleanup_type: dereferences another String object and calls unlink.
- monitor_data_type: uses the default free, so the flag has no effect.

Co-authored-by: Luke Gruber <luke.gruber@shopify.com>
2026-06-23 13:30:26 -07:00
BurdetteLamar 91ff744a25 [DOC] Harmonize join methods 2026-06-12 20:23:23 +09:00
Yaroslav Markin 35b7652058 Speed up Array#join with a memcpy fast path
When every element is a String sharing one ASCII-compatible fast-path
encoding (UTF-8/US-ASCII/ASCII-8BIT) and the separator is compatible, build
the result with a single memcpy pass instead of appending element by element
through rb_str_buf_append. Other cases fall back to the existing path.
2026-06-11 20:59:01 +02:00
Burdette Lamar b3b2492947 [DOC] Doc for frozen objects 2026-06-09 15:11:05 +09:00
Nobuyoshi Nakada be696c9c24 [Bug #22092] Improve Array#sum when the initial value is a Float 2026-06-03 11:38:38 +09:00
Alan Wu ad14452e3b [DOC] Description and soundness reasoning for Primitive.rb_jit_ary_* 2026-06-01 17:59:13 -04:00
Aaron Patterson c4d09f416c Reapply "Reserve 2 bits for expressing object layout (#17139)" (#17158)
This reverts commit ddb5055d96.
2026-06-01 19:30:58 +00:00
Aaron Patterson ddb5055d96 Revert "Reserve 2 bits for expressing object layout (#17139)"
This reverts commit 63d9f090b5.
2026-05-29 16:41:31 -07:00
63d9f090b5 Reserve 2 bits for expressing object layout (#17139)
* Reserve 2 bits for expressing object layout

We would like to make instance variable reads in the JIT compiler faster
(as well as simplify the JIT implementation).  Currently, in order to
read an instance variable, we have to:

1. Test for heap object
2. Load object to a 64 bit register
3. Mask the object header
4. Bit test against the masked header
5. JNE
6. Load field

We would like to:

1. Test for heap object
2. Load object shape to a 32 bit register
3. Bit test against the shape
4. JNE
5. Load field

The way we fetch instance variables is not consistent across objects.
In order to realize our goal, we need to encode object layout inside the
shape.  If we encode object layout inside the shape, then the shape
itself will guarantee that the access pattern generated by the JIT
compiler is correct.

We should encode the following load patterns into the shape tag bits.
This way we can share shapes on transitions, but be able to
differentiate the access patterns for the JIT compiler.  In other words,
two objects can have an `@a -> @b -> @c` transition and share the same
shape, but the tag bits can differentiate the access pattern so that the
JIT compiler can be confident that the machine code is correct.

Here are the patterns:

1. Embedded/Extended T_OBJECT Instance Variables

Objects with direct references to instance variables or via malloc
buffer

2. Objects with fields_objects fields

These are Data and TypedData objects.  They have an associated axillary
imemo/fields object that stores the instance variables.  The access
pattern is `object[2] + 2`.  The fields object is the 3rd field, and the
instance variables start at +2 inside the fields object.  The fields
object itself is a Ruby object, so it contains the usual header bits +
class headers.

3. Non Boxable Classes / Modules

This is similar to Objects with fields_objects, but the fields object is
stored at a different offset.  We’re differentiating this from boxable
classes and modules because those are harder to support.

4. Other

"Other" pattern is for objects that are rare, or have
difficult-to-implement access patterns.  This includes:

* Boxable classes and modules
* Structs (for now)
* Objects that use the geniv table

Proposed shape bit layout:

```
  Current shape_id_t is 32 bits:
  31        28 27 26 25 24 23 22        19 18                         0
  +-----------+--+--+--+--+--+------------+----------------------------+
  | unused    |L1|L0|OI|FR|CX| heap index | shape tree offset          |
  +-----------+--+--+--+--+--+------------+----------------------------+
               |  |  |  |  |  |            |
               |  |  |  |  |  |            +-- bits 0-18: SHAPE_ID_OFFSET_MASK
               |  |  |  |  |  +--------------- bits 19-22: SHAPE_ID_HEAP_INDEX_MASK
               |  |  |  |  +------------------ bit 23: SHAPE_ID_FL_COMPLEX
               |  |  |  +--------------------- bit 24: SHAPE_ID_FL_FROZEN
               |  |  +------------------------ bit 25: SHAPE_ID_FL_HAS_OBJECT_ID
               +--+--------------------------- bits 26-27: SHAPE_ID_LAYOUT_MASK
```

The important part about these layout patterns is that they do not
reflect the _type_ of object, only how the object is laid out in memory.
For example, we currently treat structs as "other", but we can refactor
them to have the same layout as "Objects with fields_objects", and when
we do that they should get a different bit in the shape header.

This commit only reserves the two bits, it doesn't use them in the JIT
compiler yet.

Co-Authored-By: John Hawthorn <john@hawthorn.email>
Co-Authored-By: Max Bernstein <tekknolagi@gmail.com>

* Update gc.c

Co-authored-by: Nobuyoshi Nakada <nobu.nakada@gmail.com>

* Update shape.h

Co-authored-by: Jean Boussier <jean.boussier@gmail.com>

* fix function name

* Update shape.c

Co-authored-by: Jean Boussier <jean.boussier@gmail.com>

* fix function name

* Revert "Update shape.c"

This reverts commit 900711defc6c541a93f3393a350819ae88cf87f1.

* add comment

---------

Co-authored-by: John Hawthorn <john@hawthorn.email>
Co-authored-by: Max Bernstein <tekknolagi@gmail.com>
Co-authored-by: Nobuyoshi Nakada <nobu.nakada@gmail.com>
Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
2026-05-29 15:09:34 -07:00
Jean Boussier 2432ed8904 Further simplify common use case of NEWOBJ_OF
Only few objects need to pass the starting shape.
2026-04-28 11:11:29 +09:00
Jean Boussier e4667e5109 Refactor NEWOB_OF for the common protected use case
Almost every objects are now WB protected, with just a few
exceptions, hence we can provide a much simpler interface.

It's also much easier to find the remaining unprotected objects.
2026-04-28 11:11:29 +09:00
Jean Boussier c202bc08e1 Simplify NEWOBJ_OF and introduce EC_NEWOBJ_OF
We only very rarely have the execution context available, so
it's preferable to provide a simpler default macro.
2026-04-28 11:11:29 +09:00
Jean Boussier e603aa0d2f Get rid of RGENGC_WB_PROTECTED_ARRAY
It has been the default for a very long time and there is no good reason to
disable it.
2026-04-28 09:39:07 +09:00
Jean Boussier 97c070c244 [DOC] Clarify array methods using eql?
[Bug #22013]

Up to a certain size, only `eql?` is used, but for larger arrays
a Hash is used an `#hash` becomes necessary.

We could consider always checking `#hash` for consistency, but
that would decrease performance.

At the very least we can clarify the documentation.
2026-04-25 12:59:05 +09:00
Jean Boussier 53099633e2 Make ruby_xfree_sized and ruby_xrealloc_sized public
[Feature #21861]
2026-04-01 08:10:07 +01:00
Nobuyoshi Nakada b6e6ccc6c2 Make Data#initialize reject Integer keys 2026-03-24 14:39:14 +09:00
Peter Zhu 752c88bab3 [DOC] Fix hash style for Array#flatten 2026-02-09 21:21:34 -05:00
Peter Zhu a4b28f14cc [DOC] Fix hash style for Array#flatten! 2026-02-09 21:21:34 -05:00
Max Bernstein f96d106d3a Don't use cexpr 2026-02-09 19:28:04 -05:00
Max Bernstein 11c845efec ZJIT: Inline Primitives for Array#each 2026-02-09 19:28:04 -05:00
Max Bernstein f96f84837d Replace ary_fetch_next with separate array iteration primitives 2026-02-09 19:28:04 -05:00
Peter Zhu 10b6d543f9 [DOC] Fix hash style in Array#to_h 2026-02-04 19:55:23 -05:00
Jean Boussier 91619f0230 gc.c: Verify provided size in rb_gc_impl_free
For now the provided size is just for GC statistics, but in the future
we may want to forward it to C23's `free_sized` and passing an incorrect
size to it is undefined behavior.
2026-01-29 23:32:04 +01:00
BurdetteLamar 21f8472e77 [DOC] Fix links in Array 2026-01-26 17:05:18 -05:00
Burdette Lamar 5230f835e8 [DOC] Harmonize #[] methods 2026-01-07 18:01:56 -05:00
Victor Shepelev ec4ca91319 Small documentation adjustments for new/updated features (#15634)
* Document Range#to_set

* Update Thread#raise and Fiber#raise signatures and docs

* Add reference to String#strip to character_selectors.rdoc

* Update *nil docs when calling methods

* Enhance Array#find and #rfind docs

* Add a notice to Kernel#raise about cause:
2025-12-20 13:07:38 +02:00
Étienne Barrié 769c6a1c54 [DOC] Use Arrays in examples for Array#find 2025-12-17 21:22:39 -08:00
Étienne Barrié bb0e42c5e7 Define Array#detect as an alias for Array#find
Otherwise Array#detect is Enumerable#detect while Array#find uses a
different more performant implementation.

[Feature #21678]
2025-12-15 10:52:43 -05:00
Kevin Newton 6147b69587 Array#rfind
Implement Array#rfind, which is the same as find except from the
other side of the Array. Also implemented Array#find (as opposed to
the generic one on Enumerable because it is significantly faster
and to keep the implementations together.

[Feature #21678]
2025-12-12 13:35:30 -05:00
Luke Gruber a211abbcbd Cache array length in rb_ary_join (#15362)
When all elements are strings, we never have to recalculate the length
of the array because there are no conversion methods that are called, so
the length will never change. This speeds up the fast path by ~10%.

```ruby
a = ["1"*10, "2"*10, "3"*10, "4"*10, "5"*10] * 10
10_000_000.times do
  a.join
end
```

```
hyperfine --warmup 1 'ruby ../ruby2/test.rb' './exe/ruby ../ruby2/test.rb'
Benchmark 1: ruby ../ruby2/test.rb
  Time (mean ± σ):      3.779 s ±  0.053 s    [User: 3.754 s, System: 0.017 s]
  Range (min … max):    3.715 s …  3.874 s    10 runs

Benchmark 2: ./exe/ruby ../ruby2/test.rb
  Time (mean ± σ):      3.411 s ±  0.038 s    [User: 3.387 s, System: 0.017 s]
  Range (min … max):    3.360 s …  3.472 s    10 runs

Summary
  ./exe/ruby ../ruby2/test.rb ran
    1.11 ± 0.02 times faster than ruby ../ruby2/test.rb
```
2025-12-02 17:35:53 -05:00
Nobuyoshi Nakada f92ff9a86b Remove an excess semicolon in a macro 2025-12-01 07:15:36 +09:00
Stan Lo 4cd6661e18 Reorganize page documentations (#15154)
Re-organize page docs
2025-11-27 20:12:24 +00:00
Peter Zhu 2380f69f68 Fix array allocation when slot size < 40 bytes
We need to allocate at least sizeof(struct RArray) when the array is
embedded on garbage collectors that support slot sizes less than 40 bytes.
2025-11-02 09:17:17 -05:00