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.
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>
Currently, this can be reproduced by:
r = Ractor.new do
a = [1, 2, 3]
a.object_id
a.dup # this frees the generic ivar for `object_id` on the copied object
:done
end
r.take
In debug builds, this hits an assertion failure without this fix.
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.
../variable.c: In function ‘iterate_over_shapes_with_callback’:
../variable.c:2189:1: warning: control reaches end of non-void function [-Wreturn-type]
2189 | }
| ^
```
variable.c: In function ‘iterate_over_shapes_with_callback’:
variable.c:2188:1: warning: control reaches end of non-void function [-Wreturn-type]
2188 | }
| ^
variable.c: In function ‘rb_field_get’:
variable.c:1322:43: warning: ‘fields_tbl’ may be used uninitialized [-Wmaybe-uninitialized]
1322 | return fields_tbl->as.shape.fields[attr_index];
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~
variable.c:1319:32: note: ‘fields_tbl’ was declared here
1319 | struct gen_fields_tbl *fields_tbl;
|
```
And get rid of the `obj_to_id_tbl`
It's no longer needed, the `object_id` is now stored inline
in the object alongside instance variables.
We still need the inverse table in case `_id2ref` is invoked, but
we lazily build it by walking the heap if that happens.
The `object_id` concern is also no longer a GC implementation
concern, but a generic implementation.
Co-Authored-By: Matt Valentine-House <matt@eightbitraptor.com>
Ivars will longer be the only thing stored inline
via shapes, so keeping the `iv_index` and `ivptr` names
would be confusing.
Instance variables won't be the only thing stored inline
via shapes, so keeping the `ivptr` name would be confusing.
`field` encompass anything that can be stored in a VALUE array.
Similarly, `gen_ivtbl` becomes `gen_fields_tbl`.
Originally, if a class was defined with the class keyword, the cref had a
const_added callback, and the superclass an inherited callback, const_added was
called first, and inherited second.
This was discussed in
https://bugs.ruby-lang.org/issues/21143
and an attempt at changing this order was made.
While both constant assignment and inheritance have happened before these
callbacks are invoked, it was deemed nice to have the same order as in
C = Class.new
This was mostly for alignment: In that last use case things happen at different
times and therefore the order of execution is kind of obvious, whereas when the
class keyword is involved, the order is opaque to the user and it is up to the
interpreter.
However, soon in
https://bugs.ruby-lang.org/issues/21193
Matz decided to play safe and keep the existing order.
This reverts commits:
de097fbe5f3df105bd2a26e72db06b0f5139bc1a
de48e47ddf78aba02fd9623bc7ce685540a10743
Using `rb_obj_clone` introduce other problems, such as `initialize_*`
callbacks invocation in the context of the parent ractor.
So we can revert back to copy the content of the object slots,
but in a way that is aware of size pools.
[Bug #20271]
[Bug #20267]
[Bug #20255]
`rb_obj_alloc(RBASIC_CLASS(obj))` will always allocate from the basic
40B pool, so if `obj` is larger than `40B`, we'll create a corrupted
object when we later copy the shape_id.
Instead we can use the same logic than ractor copy, which is
to use `rb_obj_clone`, and later ask the GC to free the original
object.
We then must turn it into a `T_OBJECT`, because otherwise
just changing its class to `RactorMoved` leaves a lot of
ways to keep using the object, e.g.:
```
a = [1, 2, 3]
Ractor.new{}.send(a, move: true)
[].concat(a) # Should raise, but wasn't.
```
If it turns out that `rb_obj_clone` isn't performant enough
for some uses, we can always have carefully crafted specialized
paths for the types that would benefit from it.
[Misc #21143]
[Bug #21193]
The previous change caused a backward compatibility issue with code
that called `Object.const_source_location` from the `inherited` callback.
To fix this, the order is now:
- Define the constant
- Invoke `inherited`
- Invoke `const_set`