225 Commits

Author SHA1 Message Date
Max Bernstein
b43e66d3b3 YJIT: Pass class and shape ID directly instead of object 2025-12-03 16:59:05 -05:00
Max Bernstein
f167073324 Move imemo fields check out of shape_get_next
Not every caller (for example, YJIT) actually needs to pass the object.
YJIT (and, in the future, ZJIT) only need to pass the class.
2025-12-03 16:59:05 -05:00
Max Bernstein
612a66805f Remove spurious obj != klass check in shape_get_next
This should never be true. I added an `rb_bug` in case it was and it
wasn't true in any of btest or test-all.

Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
2025-12-03 16:59:05 -05: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
Satoshi Tagomori
d2a587c791 renaming internal data structures and functions from namespace to box 2025-11-07 13:14:54 +09:00
Jean Boussier
05fc01188a rb_ivar_delete: allow complex transition
`rb_ivar_delete` would force a new shape to be created.
And in the case of a shape exhaustion, it wouldn't handle
T_CLASS/T_MODULE correctly.
2025-08-28 15:21:05 +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
Étienne Barrié
b0c80c2be8 Remove unused SPECIAL_CONST_SHAPE_ID
Its usage was removed in 306d50811dd060d876d1eb364a0d5e6106f5e4f1.
2025-08-21 17:41:39 +02:00
Max Bernstein
306d50811d
Don't allow looking at the shape ID of immediates (#14266)
It only makes sense for heap objects.
2025-08-18 18:58:38 -04:00
John Hawthorn
7d2b724e08 Add missing writebarrier on complex obj dup
When we dup a complex object we need to issue a writebarrier_remember
on the new object. This was caught by wbcheck inside the rubygems test
suite.

Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
2025-08-18 11:59:58 -07:00
Jean Boussier
10aa4134d4 imemo_fields: store owner object in RBasic.klass
It is much more convenient than storing the klass, especially
when dealing with `object_id` as it allows to update the id2ref
table without having to dereference the owner, which may be
garbage at that point.
2025-08-13 19:53:18 +02:00
Jean Boussier
559d9e1f67 Convert VM/shape_tree to use rb_gc_mark_and_move
The `p->field = rb_gc_location(p->field)` isn't ideal because it means all
references are rewritten on compaction, regardless of whether the referenced
object has moved. This isn't good for caches nor for Copy-on-Write.

`rb_gc_mark_and_move` avoid needless writes, and most of the time allow to
have a single function for both marking and updating references.
2025-08-07 21:00:00 +02:00
Jean Boussier
1064c63643 Fix rb_shape_transition_object_id transition to TOO_COMPLEX
If `get_next_shape_internal` fail to return a shape, we must
transitiont to a complex shape. `shape_transition_object_id`
mistakenly didn't.

Co-Authored-By: Peter Zhu <peter@peterzhu.ca>
2025-08-01 12:39:14 +02:00
John Hawthorn
54f28c1db9 Avoid concurrently overflowing of shape_id
Previously it was possible for two atomic increments of next_shape_id
running concurrently to overflow MAX_SHAPE_ID. For this reason we need
to do the test atomically with the allocation in shape_alloc returning
NULL.

This avoids overflowing next_shape_id by repeatedly attempting a CAS.
Alternatively we could have allowed incrementing past MAX_SHAPE_ID and
then clamping in rb_shapes_count, but this seems simpler.
2025-07-09 10:38:04 -07:00
John Hawthorn
cfc006d410 Always use atomics to get the shape count
When sharing between threads we need both atomic reads and writes. We
probably didn't need to use this in some cases (where we weren't running
in multi-ractor mode) but I think it's best to be consistent.
2025-07-09 10:38:04 -07:00
John Hawthorn
5dfd86cf3f Fix off-by-one in shape_tree_mark/shape_tree_compact
This was using < so subtract one from the last shape id would have us
miss the last inserted shape. I think this is unlikely to have caused
issues because I don't think the newest shape will ever have edges.

We do need to use `- 1` because otherwise RSHAPE wraps around and
returns the root shape.
2025-07-09 10:38:04 -07:00
John Hawthorn
12b0ce3875 Remove unused src param from rb_shape_copy_fields 2025-07-04 14:54:49 -07:00
Jean Boussier
242343ff80 variable.c: Refactor generic_field_set / generic_ivar_set
These two functions are very similar, they can share most of their
logic.
2025-06-26 16:25:57 +02:00
Peter Zhu
aed7a95f9d Move RUBY_ATOMIC_VALUE_LOAD to ruby_atomic.h
Deduplicates RUBY_ATOMIC_VALUE_LOAD by moving it to ruby_atomic.h.
2025-06-25 13:04:25 -04:00
Jean Boussier
b284987651 Cleanup and document shape_id_t layout 2025-06-24 16:19:16 +01: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
Jean Boussier
fb68721f63 Rename imemo_class_fields -> imemo_fields 2025-06-17 15:28:05 +02:00
ydah
2d96400c26 Fix typo in error message for shape_id verification 2025-06-15 22:35:50 +09:00
Jean Boussier
15084fbc3c Get rid of FL_EXIVAR
Now that the shape_id gives us all the same information, it's no
longer needed.
2025-06-13 23:50:30 +02: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
b51078f82e Enforce consistency between shape_id and FL_EXIVAR
The FL_EXIVAR is a bit redundant with the shape_id.
Now that the `shape_id` is embedded in all objects on all archs,
we can cheaply check if an object has any fields with a simple
bitmask.
2025-06-13 23:50:30 +02:00
Nobuyoshi Nakada
f2d7c6afee Suppress unused-variable warning 2025-06-13 22:24:09 +02:00
Jean Boussier
a99d941cac Add SHAPE_ID_HAS_IVAR_MASK for quick ivar check
This allow checking if an object has ivars with just a shape_id
mask.
2025-06-13 19:46:29 +02:00
Nobuyoshi Nakada
1d11e1be13
Suppress unused-variable warning 2025-06-13 21:09:20 +09:00
Jean Boussier
071aa02a4a shape.c: cleanup unused IDs
id_frozen and id_t_object are no longer used.
id_object_id no longer need to be exposed.
2025-06-13 12:03:22 +02:00
Jean Boussier
7c22330cd2 Allocate rb_shape_tree statically
There is no point allocating it during init, it adds
a useless indirection.
2025-06-12 17:08:22 +02:00
Jean Boussier
de4b910381 Get rid of GET_SHAPE_TREE()
It's a useless indirection.
2025-06-12 17:08:22 +02:00
Jean Boussier
e070d93573 Get rid of rb_shape_lookup 2025-06-12 17:08:22 +02:00
Jean Boussier
0292b702c4 shape.h: make RSHAPE static inline
Since the shape_tree_ptr is `extern` it should be possible to
fully inline `RSHAPE`.
2025-06-12 17:08:22 +02:00
Jean Boussier
8b5ac5abf2 Fix class instance variable inside namespaces
Now that classes fields are delegated to an object with its own
shape_id, we no longer need to mark all classes as TOO_COMPLEX.
2025-06-12 13:43:29 +02:00
Jean Boussier
3abdd4241f Turn rb_classext_t.fields into a T_IMEMO/class_fields
This behave almost exactly as a T_OBJECT, the layout is entirely
compatible.

This aims to solve two problems.

First, it solves the problem of namspaced classes having
a single `shape_id`. Now each namespaced classext
has an object that can hold the namespace specific
shape.

Second, it open the door to later make class instance variable
writes atomics, hence be able to read class variables
without locking the VM.
In the future, in multi-ractor mode, we can do the write
on a copy of the `fields_obj` and then atomically swap it.

Considerations:

  - Right now the `RClass` shape_id is always synchronized,
    but with namespace we should likely mark classes that have
    multiple namespace with a specific shape flag.
2025-06-12 07:58:16 +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
Jean Boussier
c2f2ac7db3 shape.c: Fix rb_bug call to use correct format for size_t 2025-06-11 10:10:04 +02:00
Étienne Barrié
c54e96d651 Fix RubyVM::Shape.transition_tree 2025-06-10 19:37:03 +02:00
Jean Boussier
7d8695e02f Stop pinning shape edges
Now that `rb_shape_traverse_from_new_root` has been eliminated there's
no longer any reason to pin these objects, because we no longer
need to traverse shapes downward during compaction.
2025-06-07 18:30:44 +02:00
Jean Boussier
a640723d31 Simplify rb_gc_rebuild_shape
Now that there no longer multiple shape roots, all we need to do
when moving an object from one slot to the other is to update the
`heap_index` part of the shape_id.

Since this never need to create a shape transition, it will always
work and never result in a complex shape.
2025-06-07 18:30:44 +02:00
Jean Boussier
191f6e3b87 Get rid of rb_shape_t.heap_id 2025-06-07 18:30:44 +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
2de67d424f shape.c: assert we're not returning INVALID_SHAPE_ID. 2025-06-07 18:30:44 +02:00
Jean Boussier
8c4e368dcf shape.c: ensure heap_index is consistent for complex 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
90ba2f4e1c Add missing lock around redblack_cache_ancestors
This used to be protected because all shape code was
under a lock, but now that the shape tree is lock-free
we still need to lock around the red-black cache.

Co-Authored-By: Luke Gruber <luke.gruber@shopify.com>
2025-06-06 23:07:22 +02:00
Jean Boussier
2b810ac595 shape.c: match capacity growth with T_OBJECT embedded sizes
This helps with getting with of `SHAPE_T_OBJECT`, by ensuring
that transitions will have capacities that match the next embed size.
2025-06-06 13:37:03 +02:00
Jean Boussier
3883c38979 shape.c: Fix improperly named routine
Meant to be `transition_complex` not `transition_frozen`.
2025-06-06 11:43:51 +02:00