348 Commits
Author SHA1 Message Date
ShiaandClaude Opus 5.5 8ff4ae135d Store the members directly in Data.new with positional arguments
Data.new turned positional arguments into a keyword Hash and called
initialize with it. When initialize is the default Data#initialize and
every member is given, that call can only store the members and freeze
the instance, so do that directly. A TracePoint on c_call no longer sees
Data#initialize for such calls.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 16:24:10 +02:00
ShiaandClaude Opus 5.5 f90d381de4 Read the member count from self in Struct#initialize
struct_alloc() sizes an instance by the member count of its class, so the
instance's own length can be used instead of looking the hidden
__members__ ivar up on the class again.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-19 13:13:01 +02: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 c1191af559 Raise IndexError for an out-of-range Struct index past Fixnum
rb_struct_pos hands an out-of-range numeric index back through LEN2NUM, which makes a Bignum past the Fixnum range, and invalid_struct_pos then treated it as a member name and raised NameError.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:00:15 +09:00
Hiroshi SHIBATAandClaude Opus 5 cfabfcd520 Use rb_len_t for lengths and indices of Struct
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
Max Bernstein e4c5526a55 ZJIT: Inline Struct#initialize (#19119)
For small-enough Struct instances (<= 256 members, to avoid generating too much code), inline the initialize method.

This makes creating and initializing Structs very very fast and also gives more information to the load-store pass since the process is less opaque.

It's mostly just a frozen-ness check and a bunch of stores.

```
--------------------  ------------  ------------  --------------  -------------
bench                  master (ms)   branch (ms)  branch 1st itr  master/branch
lee                   129.1 ± 1.3%  117.8 ± 1.4%           1.060          1.096
struct-new-no-escape   38.5 ± 1.8%   19.8 ± 1.3%           1.393          1.949
--------------------  ------------  ------------  --------------  -------------
```

(Following https://github.com/ruby/ruby/pull/18835 )
2026-10-01 22:29:55 +00:00
Max Bernstein e77b7b6f1e ZJIT: Specialize Struct class .new (#18835)
We can use `ObjectAllocClass` for Structs because they are basically
a `__members__` ivar lookup for sizing plus the default allocator.

Requires #18888 to make sure the constructor does not raise.
2026-09-22 15:52:19 -04:00
Max Bernstein 1070504b89 Make non-Array Struct __members__ a bug (#18888)
We should not ever hit this from Ruby code; user code cannot modify
ivars that do not start with @.

This makes `num_members` leaf and therefore Struct class allocation also
leaf.
2026-09-22 09:39:58 -04:00
Jean Boussier 2f72b3d142 struct.c: Strop reserving extra space for ivars
[Bug #22292]

This was a leftover 6f339aebfe
2026-09-06 09:22:55 +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 60fb0baeaf Define Range#begin and Range#end as optimized methods
Since Range is a struct, might as well use optimized accessors.
2026-07-21 16:47:19 +02:00
Jean BoussierandJohn Hawthorn 40f105bd55 Change RStruct to match SHAPE_ID_LAYOUT_EXTENDED
THe downside is that we now always reserve one 8B reference for the
IMEMO/fields, even for structs that never have any ivars.

But it is an acceptable tradeoff given that ivars on structs aren't
rare.

Co-Authored-By: John Hawthorn <john@hawthorn.email>
2026-07-21 08:30:12 +02:00
Nobuyoshi Nakada 529d86a2c3 Format unknown struct keywords as a Ruby string 2026-07-15 13:28:39 +09:00
Peter Zhu 916d8c1050 Prevent overflow of length bits for embedded structs
Embedded structs 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 struct_alloc.
2026-07-11 15:20:59 +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
Matt Valentine-House 5465dca954 Prefer rb_sym2str over rb_id2str(SYM2ID) 2026-06-24 22:15:52 +01:00
Peter Zhu f916141a2d [DOC] Fix hash style for Struct 2026-06-02 20:12:28 +09:00
Jean Boussier deceb9f62e Rename rb_shape_obj_* into rb_obj_shape_*
For consistency.
2026-05-06 10:10:16 +02: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 9307d1b5b6 Get rid of RGENGC_WB_PROTECTED_STRUCT
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
Nobuyoshi Nakada b6e6ccc6c2 Make Data#initialize reject Integer keys 2026-03-24 14:39:14 +09:00
Junichi Ito a668f4bf2e Improve missing keyword detection in Data#initialize
- Treat symbol and string keys equivalently when detecting missing keywords
- Consider index keys when detecting missing keywords in Data#initialize
2026-03-24 14:37:24 +09:00
Peter Zhu 491e38902c [DOC] Fix links to What's Here
The RDoc link format has changed so these are all broken links.
2026-01-26 17:18:19 -05:00
Jean Boussier 73be9992e9 Disambiguate private and public RSTRUCT_ helpers
RSTRUCT_LEN / RSTRUCT_GET / RSTRUCT_SET all existing in two
versions, one public that does type and frozens checks
and one private that doesn't.

The problem is that this is error prone because the public version
is always accessible, but the private one require to include
`internal/struct.h`. So you may have some code that rely on the
public version, and later on the private header is included and
changes the behavior.

This already led to introducing a bug in YJIT & ZJIT:
https://github.com/ruby/ruby/pull/15835
2026-01-11 13:03:03 +01:00
Burdette Lamar 58fb95af36 [DOC] Harmonize #== methods (#15805) 2026-01-06 17:13:15 -05:00
Shannon Skipper 65f9c4a06a Drop memberless Data/Struct#inspect trailing space
Anonymous memberless Structs and Data were returning `#<struct >` and
`#<data >` with a trailing space. Now they return `#<struct>` and
`#<data>` to match attrless class behavior and look a bit more compact.
2026-01-03 18:12:44 +09:00
Nobuyoshi Nakada d7a6ff8224 [Bug #21819] Data objects without members should also be frozen 2026-01-03 15:03:57 +09:00
Peter Zhu 8f9838476d Fix fields object in embedded struct
We don't set RSTRUCT_GEN_FIELDS when RCLASS_MAX_IV_COUNT(klass) != 0, so
we need to set RSTRUCT_SET_FIELDS_OBJ to 0 otherwise it may have an
invalid value and crash.
2025-12-05 15:40:39 -08:00
Jean Boussier 8c3909935e Handle NEWOBJ tracepoints settings fields
[Bug #21710]

- struct.c: `struct_alloc`

It is possible for a `NEWOBJ` tracepoint call back to write fields
into a newly allocated object before `struct_alloc` had the time
to set the `RSTRUCT_GEN_FIELDS` flags and such.

Hence we can't blindly initialize the `fields_obj` reference to `0`
we first need to check no fields were added yet.

- object.c: `rb_class_allocate_instance`

Similarly, if a `NEWOBJ` tracepoint tries to set fields on the object,
the `shape_id` must already be set, as it's required on T_OBJECT to
know where to write fields.

`NEWOBJ_OF` had to be refactored to accept a `shape_id`.
2025-12-03 08:14:56 +01:00
John Hawthorn 8eaa9eb3eb Clear fields on heap RStruct before allocating
Now that we no longer explicitly set the first three elements, we need
to ensure the object is in a state safe for GC before we call
struct_heap_alloc, which may GC.
2025-10-03 10:30:14 -07:00
Peter Zhu a456e79e06 Clear out memory for newly allocated structs 2025-09-17 09:25:17 -04:00
Jean BoussierandÉtienne Barrié f3206cc79b Struct: keep direct reference to IMEMO/fields when space allows
It's not rare for structs to have additional ivars, hence are one
of the most common, if not the most common type in the `gen_fields_tbl`.

This can cause Ractor contention, but even in single ractor mode
means having to do a hash lookup to access the ivars, and increase
GC work.

Instead, unless the struct is perfectly right sized, we can store
a reference to the associated IMEMO/fields object right after the
last struct member.

```
compare-ruby: ruby 3.5.0dev (2025-08-06T12:50:36Z struct-ivar-fields-2 9a30d141a1) +PRISM [arm64-darwin24]
built-ruby: ruby 3.5.0dev (2025-08-06T12:57:59Z struct-ivar-fields-2 2ff3ec237f) +PRISM [arm64-darwin24]
warming up.....

|                      |compare-ruby|built-ruby|
|:---------------------|-----------:|---------:|
|member_reader         |    590.317k|  579.246k|
|                      |       1.02x|         -|
|member_writer         |    543.963k|  527.104k|
|                      |       1.03x|         -|
|member_reader_method  |    213.540k|  213.004k|
|                      |       1.00x|         -|
|member_writer_method  |    192.657k|  191.491k|
|                      |       1.01x|         -|
|ivar_reader           |    403.993k|  569.915k|
|                      |           -|     1.41x|
```

Co-Authored-By: Étienne Barrié <etienne.barrie@gmail.com>
2025-08-06 17:07:49 +02:00
Nobuyoshi Nakada 2e7e78cd59 [Bug #21440] Stop caching member list in frozen Data/Struct class 2025-06-13 14:22:06 +09:00
Shannon Skipper 841555245d [DOC] Show NONE within Measure namespace (#12274)
Keep `NONE` within `Measure`
2025-01-09 13:53:49 +09:00
Nobuyoshi Nakada e433e6515e [DOC] Exclude 'Class' and 'Module' from RDoc's autolinking 2025-01-02 12:36:06 +09:00
Nobuyoshi Nakada b4ec22fe6c [DOC] Exclude 'Method' from RDoc's autolinking 2025-01-02 12:23:49 +09:00
John Bampton 3fc1495c30 Fix spelling 2024-10-09 07:14:44 +09:00
BurdetteLamar ccd35eaecf [DOC] Rationalize aliases in What's Here 2024-09-10 14:00:00 -04:00
Jean Boussier f06670c5a2 Eliminate usage of OBJ_FREEZE_RAW
Previously it would bypass the `FL_ABLE` check, but
since shapes introduction, it started having a different
behavior than `OBJ_FREEZE`, as it would onyl set the `FL_FREEZE`
flag, but not update the shape.

I have no indication of this causing a bug yet, but it seems
like a trap waiting to happen.
2024-04-16 17:20:35 +02:00
Jean Boussier d4f3dcf4df Refactor VM root modules
This `st_table` is used to both mark and pin classes
defined from the C API. But `vm->mark_object_ary` already
does both much more efficiently.

Currently a Ruby process starts with 252 rooted classes,
which uses `7224B` in an `st_table` or `2016B` in an `RArray`.

So a baseline of 5kB saved, but since `mark_object_ary` is
preallocated with `1024` slots but only use `405` of them,
it's a net `7kB` save.

`vm->mark_object_ary` is also being refactored.

Prior to this changes, `mark_object_ary` was a regular `RArray`, but
since this allows for references to be moved, it was marked a second
time from `rb_vm_mark()` to pin these objects.

This has the detrimental effect of marking these references on every
minors even though it's a mostly append only list.

But using a custom TypedData we can save from having to mark
all the references on minor GC runs.

Addtionally, immediate values are now ignored and not appended
to `vm->mark_object_ary` as it's just wasted space.
2024-03-06 15:33:43 -05:00
Jean Boussier e626da82ea Don't pin named structs defined in Ruby
[Bug #20311]

`rb_define_class_under` assumes it's called from C and that the
reference might be held in a C global variable, so it adds the
class to the VM root.

In the case of `Struct.new('Name')` it's wasteful and make
the struct immortal.
2024-03-01 08:23:38 +01:00
Yusuke Endoh 25d74b9527 Do not include a backtick in error messages and backtraces
[Feature #16495]
2024-02-15 18:42:31 +09:00
Burdette Lamar 8c5b9ebf71 [DOC] Improve doc guide compliance (#8221) 2023-08-15 14:43:58 -04:00
Peter Zhu 1e7b67f733 [Feature #19730] Remove transient heap 2023-07-13 09:27:33 -04:00
Nobuyoshi Nakada 9c1fe9064c [Feature #19757] Add new API rb_data_define 2023-07-13 17:55:55 +09:00
Nobuyoshi Nakada b934976024 Prefer 0 over NULL as function pointers
SunC warns use of `NULL`, pointer to data as function pointers.
2023-06-23 03:15:55 +09:00
Matt Valentine-House 6fe46ff967 When alloc size is too large, only allocate struct 2023-06-12 16:20:05 +02:00
Peter Zhu 2543a6573f Implement Struct on VWA
The benchmark results show that this feature has either a positive or
no impact on performance. The memory usage is also mostly unchanged,
except in hexapdf, where there is a decrease in RSS.

--------------  -----------  ----------  ---------  -----------  ----------  ---------  --------------  -------------
bench           master (ms)  stddev (%)  RSS (MiB)  branch (ms)  stddev (%)  RSS (MiB)  branch 1st itr  master/branch
activerecord    70.8         2.2         56.0       71.7         2.2         56.0       0.99            0.99
erubi_rails     20.5         13.6        94.7       20.5         14.3        94.2       0.93            1.00
hexapdf         2541.0       0.7         212.8      2544.4       0.7         203.4      1.00            1.00
liquid-c        65.6         0.3         38.9       65.3         0.3         38.9       1.01            1.01
liquid-compile  63.7         0.3         34.6       61.1         0.2         34.6       1.04            1.04
liquid-render   163.1        0.1         37.1       163.3        0.1         37.1       1.00            1.00
mail            139.3        0.1         50.5       137.0        0.1         50.1       0.99            1.02
psych-load      2065.7       0.1         36.9       2068.2       0.1         37.3       1.00            1.00
railsbench      2034.6       0.5         103.9      2031.9       0.5         103.8      1.02            1.00
ruby-lsp        65.3         3.1         89.8       66.2         3.0         89.7       1.01            0.99
sequel          73.2         1.0         40.3       73.4         1.0         40.3       1.00            1.00
--------------  -----------  ----------  ---------  -----------  ----------  ---------  --------------  -------------
2023-06-05 15:47:16 -04:00