summaryrefslogtreecommitdiff
path: root/shape.h
AgeCommit message (Collapse)Author
4 hoursTurn `rb_classext_t.fields` into a T_IMEMO/class_fieldsJean Boussier
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. Notes: Merged: https://github.com/ruby/ruby/pull/13411
20 hoursRefactor the last references to `rb_shape_t`Jean Boussier
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`. Notes: Merged: https://github.com/ruby/ruby/pull/13586
22 hoursshape.h: remove YJIT workaroundJean Boussier
YJIT x86 backend would crahs if the shape_id top bit was set. This should have been fixed now. Notes: Merged: https://github.com/ruby/ruby/pull/13585
5 daysSimplify `rb_gc_rebuild_shape`Jean Boussier
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. Notes: Merged: https://github.com/ruby/ruby/pull/13556
5 daysGet rid of rb_shape_t.heap_idJean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13556
5 daysGet rid of SHAPE_T_OBJECTJean Boussier
Now that we have the `heap_index` in shape flags we no longer need `T_OBJECT` shapes. Notes: Merged: https://github.com/ruby/ruby/pull/13556
5 daysRemove EMBEDDED shape_id flagsJean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13556
5 daysLeave the shape_id_t highest bit unused to avoid crashing YJITJean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13556
5 daysReplicate `heap_index` in shape_id flags.Jean Boussier
This is preparation to getting rid of `T_OBJECT` transitions. By first only replicating the information it's easier to ensure consistency. Notes: Merged: https://github.com/ruby/ruby/pull/13556
7 daysRefactor raw accesses to rb_shape_t.capacityJean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13524
7 daysGet rid of `rb_shape_t.flags`Jean Boussier
Now all flags are only in the `shape_id_t`, and can all be checked without needing to dereference a pointer. Notes: Merged: https://github.com/ruby/ruby/pull/13515
8 daysGet rid of TOO_COMPLEX shape typeJean Boussier
Instead it's now a `shape_id` flag. This allows to check if an object is complex without having to chase the `rb_shape_t` pointer. Notes: Merged: https://github.com/ruby/ruby/pull/13511
8 daysvm_getivar: normalize shape_id to ignore frozen stateJean Boussier
Freezing an object changes its `shape_id` This is necessary so that `setivar` routines can use the `shape_id` as a cache key and save on checking the frozen status every time. However for `getivar` routines, this causes needless cache misses. By clearing that bit we increase hit rate in codepaths that see both frozen and mutable objects. Notes: Merged: https://github.com/ruby/ruby/pull/13289
8 daysGet rid of frozen shapes.Jean Boussier
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. Notes: Merged: https://github.com/ruby/ruby/pull/13289
9 daysUse all 32bits of `shape_id_t` on all platformsJean Boussier
Followup: https://github.com/ruby/ruby/pull/13341 / [Feature #21353] Even thought `shape_id_t` has been make 32bits, we were still limited to use only the lower 16 bits because they had to fit alongside `attr_index_t` inside a `uintptr_t` in inline caches. By enlarging inline caches we can unlock the full 32bits on all platforms, allowing to use these extra bits for tagging. Notes: Merged: https://github.com/ruby/ruby/pull/13500
10 daysshape.c: Implement a lock-free version of get_next_shape_internalJean Boussier
Whenever we run into an inline cache miss when we try to set an ivar, we may need to take the global lock, just to be able to lookup inside `shape->edges`. To solve that, when we're in multi-ractor mode, we can treat the `shape->edges` as immutable. When we need to add a new edge, we first copy the table, and then replace it with CAS. This increases memory allocations, however we expect that creating new transitions becomes increasingly rare over time. ```ruby class A def initialize(bool) @a = 1 if bool @b = 2 else @c = 3 end end def test @d = 4 end end def bench(iterations) i = iterations while i > 0 A.new(true).test A.new(false).test i -= 1 end end if ARGV.first == "ractor" ractors = 8.times.map do Ractor.new do bench(20_000_000 / 8) end end ractors.each(&:take) else bench(20_000_000) end ``` The above benchmark takes 27 seconds in Ractor mode on Ruby 3.4, and only 1.7s with this branch. Co-Authored-By: Étienne Barrié <[email protected]> Notes: Merged: https://github.com/ruby/ruby/pull/13441
2025-05-28Refactor attr_index_t cachesJean Boussier
Ensure the same helpers are used for packing and unpacking. Notes: Merged: https://github.com/ruby/ruby/pull/13455
2025-05-27Rename `rb_shape_id_canonical_p` -> `rb_shape_canonical_p`Jean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13450
2025-05-27Rename `rb_shape_set_shape_id` in `rb_obj_set_shape_id`Jean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13450
2025-05-27Refactor `rb_shape_too_complex_p` to take a `shape_id_t`.Jean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13450
2025-05-27Refactor `rb_shape_has_object_id`Jean Boussier
Now takes a `shape_id_t` and the version that takes a `rb_shape_t *` is private. Notes: Merged: https://github.com/ruby/ruby/pull/13450
2025-05-27Refactor `rb_obj_shape` out.Jean Boussier
It still exists but only in `shape.c`. Notes: Merged: https://github.com/ruby/ruby/pull/13450
2025-05-27Get rid of rb_shape_set_shapeJean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13450
2025-05-27Refactor `rb_shape_get_iv_index` to take a `shape_id_t`Jean Boussier
Further reduce exposure of `rb_shape_t`. Notes: Merged: https://github.com/ruby/ruby/pull/13450
2025-05-27Get rid of `rb_shape_id(rb_shape_t *)`Jean Boussier
We should avoid conversions from `rb_shape_t *` into `shape_id_t` outside of `shape.c` as the short term goal is to have `shape_id_t` contain tags. Notes: Merged: https://github.com/ruby/ruby/pull/13448
2025-05-27Get rid of `rb_shape_canonical_p`Jean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13448
2025-05-27Refactor `rb_shape_rebuild_shape` to stop exposing `rb_shape_t`Jean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13448
2025-05-26Add shape_id to RBasic under 32 bitJohn Hawthorn
This makes `RBobject` `4B` larger on 32 bit systems but simplifies the implementation a lot. [Feature #21353] Co-authored-by: Jean Boussier <[email protected]> Notes: Merged: https://github.com/ruby/ruby/pull/13341
2025-05-23Refactor `rb_shape_transition_remove_ivar`Jean Boussier
Move the fields management logic in `rb_ivar_delete`, and keep shape managment logic in `rb_shape_transition_remove_ivar`. Notes: Merged: https://github.com/ruby/ruby/pull/13426
2025-05-15Ensure shape_id is never used on T_IMEMOJean Boussier
It doesn't make sense to set ivars or anything shape related on a T_IMEMO. Co-Authored-By: John Hawthorn <[email protected]> Notes: Merged: https://github.com/ruby/ruby/pull/13347
2025-05-13variable.c: Refactor rb_obj_field_* to take shape_id_tJean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13314
2025-05-09Refactor `FIRST_T_OBJECT_SHAPE_ID` to not be used outside `shape.c`Jean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13291
2025-05-09Rename `RB_OBJ_SHAPE` -> `rb_obj_shape`Jean Boussier
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. Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-09Stop exposing rb_shape_frozen_shape_pJean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-09Get rid of `rb_shape_get_parent`.Jean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-09Rename `rb_shape_get_shape_id` -> `RB_OBJ_SHAPE_ID`Jean Boussier
And `rb_shape_get_shape` -> `RB_OBJ_SHAPE`. Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-09Remove unused `rb_shape_object_id_index`Jean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-09Refactor `rb_shape_get_next` to return an IDJean Boussier
Also rename it, and change parameters to be consistent with other transition functions. Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-09Refactor `rb_shape_transition_shape_remove_ivar` to not take a shape pointerJean Boussier
It's more consistent with other transition functions. Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-09Rename `rb_shape_obj_too_complex` -> `rb_shape_obj_too_complex_p`Jean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-09Refactor `rb_shape_transition_too_complex` to return an ID.Jean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-09Refactor `rb_shape_transition_frozen` to return a `shape_id`.Jean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-09Get rid of useless SHAPE_MASKJean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-09Rename `rb_shape_get_shape_by_id` -> `RSHAPE`Jean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-09Refactor `rb_shape_get_next_iv_shape` to take and return ids.Jean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-09Stop exposing rb_shape_get_root_shapeJean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-09Remove unused rb_obj_debug_shapeJean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-09Refactor `rb_shape_depth` to take an ID rather than a pointer.Jean Boussier
As well as `rb_shape_edges_count` and `rb_shape_memsize`. Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-09Refactor `rb_shape_traverse_from_new_root` to not expose `rb_shape_t`Jean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13283
2025-05-09Extract `rb_shape_free_all`Jean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13283