887 Commits
Author SHA1 Message Date
John Hawthorn 6fd2ae629a Add and use rb_ivar_foreach_buffered
Previously, rb_ivar_foreach would walk up the shape tree, but yield
instance variables to the callback as it went. If the object shape was
modified during this callback, particularly with removing an instance
variable, it could result in reading free'd memory.

This commit solves this by adding a version which buffering all instance
variable names and values before calling the callback, giving a snapshot
of the object at the time rb_ivar_foreach_buffered is called.

The buffer is made with ALLOCV_N, so the performance difference should
be minimal, and I don't think this method is particuarly heavily used.

I also added a missing variable assignment fixed by 96cd1bc765.

[Bug #21996] (Backport)
2026-06-10 12:59:53 -07:00
Burdette Lamar 2d69facd20 [DOC] Tweaks for Object#<=> 2025-12-21 14:05:38 -05:00
BurdetteLamar 7c1e37cfe1 [DOC] Tweaks for Module#<=> 2025-12-20 18:12:56 -05:00
Burdette Lamar b14f2f0116 [DOC] Harmonize lt methods 2025-12-18 19:21:00 -05:00
John Hawthorn 459c377222 Assume result from allocator will be valid
This adds a fastpath in class_call_alloc_func to simply return if the
class matches the one expected.

I think we could probably just remove this check, or move it to the debug
build.
2025-12-11 09:53:10 -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
Burdette Lamar 005fba0713 [DOC] Tweaks for Module#<=> 2025-11-28 20:27:35 -05:00
Jean Boussier 191bfcb9c5 Define Kernel#instance_variables_to_inspect
[Bug #21718]

Otherwise objects that don't define it, but define a fairly liberal
`method_missing` method will run into errors that are hard to understand:

```ruby
class Foo
  def method_missing(name, ...)
    name
  end
end

p Foo.new.inspect
```

```
'Kernel#inspect': wrong argument type Symbol (expected Array) (TypeError)
	from ../test.rb:7:in '<main>'
```
2025-11-28 18:34:59 +01:00
Stan Lo 4cd6661e18 Reorganize page documentations (#15154)
Re-organize page docs
2025-11-27 20:12:24 +00:00
Max Bernstein bacb687fd7 ZJIT: Call instance allocation function directly 2025-09-17 17:27:35 -04:00
Max Bernstein 88e0ac35a3 ZJIT: Prevent custom allocator in ObjectAllocClass 2025-09-17 17:27:35 -04:00
Jeremy Evans 5c7dfe85a1 Initialize class dup/clone before calling initialize_dup/initialize_clone
Previously, you could override the class initialize_dup/initialize_clone
method and the class hierarchy would not be set correctly inside the
method before calling super.

This removes Module#initialize_copy, and instead makes Object#dup/clone
call the underlying C function (rb_mod_init_copy) before calling the
appropriate initialize_dup/initialize_clone method.

This results in the following fixes:

* The appropriate initialize_dup method is called (dup on a class
  will respect superclass initialize_dup).

* Inside class initialize_dup/initialize_clone/initialize_copy,
  class ancestor hierarchy is correct.

* Calling singleton_class inside initialize_dup no longer raises
  a TypeError later in dup.

* Calling singleton_class.ancestors inside initialize_dup no
  longer results in missing ancestors.

Fixes [Bug #21538]
2025-08-30 11:24:25 -07:00
Jean Boussier 395bda2fa1 object.c: make rb_obj_class_must static inline 2025-08-30 14:17:14 +02:00
Jean Boussier d89e73471d object.c: refactor rb_obj_class and rb_class_real 2025-08-30 14:14:10 +02:00
Jean Boussier f5da6395bd Kernel#class skip null check
`Kernel#class` can't possibly be called on an hidden object,
hence we don't need to check for `klass == 0`.

```
compare-ruby: ruby 3.5.0dev (2025-08-30T01:45:42Z obj-class 01a57bd6cd) +YJIT +PRISM [arm64-darwin24]
built-ruby: ruby 3.5.0dev (2025-08-30T10:21:10Z obj-class b67c16c477) +YJIT +PRISM [arm64-darwin24]

|           |compare-ruby|built-ruby|
|:----------|-----------:|---------:|
|obj        |     445.217|   642.446|
|           |           -|     1.44x|
|extended   |     136.826|   117.974|
|           |       1.16x|         -|
|singleton  |     166.269|   166.695|
|           |           -|     1.00x|
|immediate  |     380.243|   515.775|
|           |           -|     1.36x|
```
2025-08-30 14:14:10 +02:00
Jean Boussier 01b89528cb object.c: improve fake_class_p to also handle T_MODULE
This requires ensuring T_MODULE never has FL_SINGLETON set,
so RMODULE_IS_REFINEMENT had to be moved.
2025-08-30 14:14:10 +02:00
Jean Boussier fd0c772db7 Micro-optimize Object#class
Since `BUILTIN_TYPE` and `RCLASS_SINGLETON_P` are both stored in
`RBasic.flags`, we can combine these two checks in a single bitmask.

This rely on `T_ICLASS` and `T_CLASS` not overlapping, and assume
`klass` is always either of these types.

Just combining the masks brings a small but consistent 1.08x speedup on the simple case benchmark.

```
compare-ruby: ruby 3.5.0dev (2025-08-30T01:45:42Z obj-class 01a57bd6cd) +YJIT +PRISM [arm64-darwin24]
built-ruby: ruby 3.5.0dev (2025-08-30T09:56:24Z obj-class 2685f8dbb4) +YJIT +PRISM [arm64-darwin24]

|           |compare-ruby|built-ruby|
|:----------|-----------:|---------:|
|obj        |     444.410|   478.895|
|           |           -|     1.08x|
|extended   |     135.139|   140.206|
|           |           -|     1.04x|
|singleton  |     165.155|   155.832|
|           |       1.06x|         -|
|immediate  |     380.103|   432.090|
|           |           -|     1.14x|
```

But with the RB_UNLIKELY compiler hint, it's much more significant, however
the singleton and enxtended cases are slowed down.
However we can assume the simple case is way more common than the other two.

```
compare-ruby: ruby 3.5.0dev (2025-08-30T01:45:42Z obj-class 01a57bd6cd) +YJIT +PRISM [arm64-darwin24]
built-ruby: ruby 3.5.0dev (2025-08-30T09:51:01Z obj-class 12d01a1b02) +YJIT +PRISM [arm64-darwin24]

|           |compare-ruby|built-ruby|
|:----------|-----------:|---------:|
|obj        |     444.951|   556.191|
|           |           -|     1.25x|
|extended   |     136.836|   113.871|
|           |       1.20x|         -|
|singleton  |     166.335|   167.747|
|           |           -|     1.01x|
|immediate  |     379.642|   509.515|
|           |           -|     1.34x|
```
2025-08-30 14:14:10 +02:00
Jean Boussier 5257e1298c Replace ROBJECT_EMBED by ROBJECT_HEAP
The embed layout is way more common than the heap one,
especially since WVA.

I think it makes for more readable code to inverse the
flag.
2025-08-27 12:41:07 +02:00
Jean Boussier 14bdf4b57d Ensure T_OBJECT and T_IMEMO/fields have identical layout 2025-08-26 13:44:59 +02:00
Jean Boussier f1727b5b67 Get rid of rb_obj_set_shape_id
Now that the shape_id has been unified across all types
this helper function doesn't do much over `RBASIC_SET_SHAPE_ID`.

It still check if the write is needed, but it doesn't seem useful
in places where it's used.
2025-08-25 14:46:29 +02:00
Peter Zhu 1055e04e28 Remove useless set of dest_shape_id in rb_obj_copy_ivar 2025-07-31 23:22:25 -04:00
Nobuyoshi Nakada abafb662ea Adjust indents [ci skip] 2025-07-26 22:07:28 +09:00
John Hawthorn 12b0ce3875 Remove unused src param from rb_shape_copy_fields 2025-07-04 14:54:49 -07:00
Jean Boussier 45a2c95d0f Reduce exposure of FL_FREEZE
The `FL_FREEZE` flag is redundant with `SHAPE_ID_FL_FROZEN`, so
ideally it should be eliminated in favor of the later.

Doing so would eliminate the risk of desync between the two, but
also solve the problem of the frozen status being global in namespace
context (See Bug #21330).
2025-06-24 11:29:39 +01:00
ydah 251cfdfe22 Fix typo in rb_bug message for unreachable code 2025-06-15 22:35:26 +09:00
Jean Boussier 6dbe24fe56 Use the shape_id rather than FL_EXIVAR
We still keep setting `FL_EXIVAR` so that `rb_shape_verify_consistency`
can detect discrepancies.
2025-06-13 23:50:30 +02:00
Jean Boussier 95201299fd Refactor the last references to rb_shape_t
The type isn't opaque because Ruby isn't often compiled with LTO,
so for optimization purpose it's better to allow as much inlining
as possible.

However ideally only `shape.c` and `shape.h` should deal with
the actual struct, and everything else should just deal with opaque
`shape_id_t`.
2025-06-11 16:38:38 +02:00
Nobuyoshi NakadaandJean Boussier f4135feafc [Feature #21219] Selective inspect of instance variables
Make Kernel#inspect ask which instance variables should be dumped by
the result of `#instance_variables_to_inspect`.

Co-Authored-By: Jean Boussier <byroot@ruby-lang.org>
2025-06-09 09:25:37 +02:00
Jean Boussier 6eb0cd8df7 Get rid of SHAPE_T_OBJECT
Now that we have the `heap_index` in shape flags we no longer
need `T_OBJECT` shapes.
2025-06-07 18:30:44 +02:00
Jean Boussier 689ec51146 Replicate heap_index in shape_id flags.
This is preparation to getting rid of `T_OBJECT` transitions.
By first only replicating the information it's easier to ensure
consistency.
2025-06-07 18:30:44 +02:00
Jean Boussier 4e39580992 Refactor raw accesses to rb_shape_t.capacity 2025-06-05 22:06:15 +02:00
Jean Boussier 625d6a9cbb Get rid of frozen shapes.
Instead `shape_id_t` higher bits contain flags, and the first one
tells whether the shape is frozen.

This has multiple benefits:
  - Can check if a shape is frozen with a single bit check instead of
    dereferencing a pointer.
  - Guarantees it is always possible to transition to frozen.
  - This allow reclaiming `FL_FREEZE` (not done yet).

The downside is you have to be careful to preserve these flags
when transitioning.
2025-06-04 07:59:20 +02:00
John Hawthorn d1343e12d2 Use flag for RCLASS_IS_INITIALIZED
Previously we used a flag to set whether a module was uninitialized.
When checked whether a class was initialized, we first had to check that
it had a non-zero superclass, as well as that it wasn't BasicObject.

With the advent of namespaces, RCLASS_SUPER is now an expensive
operation, and though we could just check for the prime superclass, we
might as well take this opportunity to use a flag so that we can perform
the initialized check with as few instructions as possible.

It's possible in the future that we could prevent uninitialized classes
from being available to the user, but currently there are a few ways to
do that.
2025-05-28 11:44:07 -04:00
Jean Boussier 326c120aa7 Rename rb_shape_id_canonical_p -> rb_shape_canonical_p 2025-05-27 15:34:02 +02:00
Jean Boussier 925dec8d70 Rename rb_shape_set_shape_id in rb_obj_set_shape_id 2025-05-27 15:34:02 +02:00
Jean Boussier ccf2b7c5b8 Refactor rb_shape_too_complex_p to take a shape_id_t. 2025-05-27 15:34:02 +02:00
Jean Boussier a80a5000ab Refactor rb_obj_shape out.
It still exists but only in `shape.c`.
2025-05-27 15:34:02 +02:00
Jean Boussier 8b0868cbb1 Refactor rb_shape_rebuild_shape to stop exposing rb_shape_t 2025-05-27 12:45:24 +02:00
John HawthornandJean Boussier f483befd90 Add shape_id to RBasic under 32 bit
This makes `RBobject` `4B` larger on 32 bit systems
but simplifies the implementation a lot.

[Feature #21353]

Co-authored-by: Jean Boussier <byroot@ruby-lang.org>
2025-05-26 10:31:54 +02:00
John Hawthorn e01e89f55c Avoid calling RCLASS_SUPER in rb_class_superclass 2025-05-23 10:22:24 -07:00
Jean Boussier 22c09135a8 rb_copy_generic_ivar: reset shape_id when no ivar are present 2025-05-16 20:16:52 +02:00
Jean Boussier ec8900e3eb rb_gc_impl_copy_finalizer: generate a new object id
Fix a regression introduced by: https://github.com/ruby/ruby/pull/13155
2025-05-16 20:16:52 +02:00
John Hawthorn b0502e8f90 Remove respond_to check from Class#bind_call 2025-05-12 14:10:29 -07:00
Satoshi Tagomori 8ecc04dc04 Delete code for debugging namespace 2025-05-11 23:32:50 +09:00
Satoshi Tagomori 382645d440 namespace on read 2025-05-11 23:32:50 +09:00
Jean Boussier 3135eddb4e Refactor FIRST_T_OBJECT_SHAPE_ID to not be used outside shape.c 2025-05-09 20:45:48 +02:00
Jean Boussier ea77250847 Rename RB_OBJ_SHAPE -> rb_obj_shape
As well as `RB_OBJ_SHAPE_ID` -> `rb_obj_shape_id`
and `RSHAPE` is now a simple alias for `rb_shape_lookup`.

I tried to turn all these into `static inline` but I'm having
trouble with `RUBY_EXTERN rb_shape_tree_t *rb_shape_tree_ptr;`
not being exposed as I'd expect.
2025-05-09 10:22:51 +02:00
Jean Boussier 5782561fc1 Rename rb_shape_get_shape_id -> RB_OBJ_SHAPE_ID
And `rb_shape_get_shape` -> `RB_OBJ_SHAPE`.
2025-05-09 10:22:51 +02:00
Jean Boussier 3f7c0af051 Rename rb_shape_obj_too_complex -> rb_shape_obj_too_complex_p 2025-05-09 10:22:51 +02:00
Jean Boussier f82523f14b Refactor rb_shape_transition_frozen to return a shape_id. 2025-05-09 10:22:51 +02:00