summaryrefslogtreecommitdiff
path: root/shape.h
AgeCommit message (Collapse)Author
2025-12-05Revert "gc.c: Pass shape_id to `newobj_init`"Peter Zhu
This reverts commit 228d13f6ed914d1e7f6bd2416e3f5be8283be865. This commit makes default.c and mmtk.c depend on shape.h, which prevents them from building independently.
2025-12-03YJIT: Pass class and shape ID directly instead of objectMax Bernstein
2025-12-03gc.c: Pass shape_id to `newobj_init`Jean Boussier
Attempt to fix the following SEGV: ``` ruby(gc_mark) ../src/gc/default/default.c:4429 ruby(gc_mark_children+0x45) [0x560b380bf8b5] ../src/gc/default/default.c:4625 ruby(gc_mark_stacked_objects) ../src/gc/default/default.c:4647 ruby(gc_mark_stacked_objects_all) ../src/gc/default/default.c:4685 ruby(gc_marks_rest) ../src/gc/default/default.c:5707 ruby(gc_marks+0x4e7) [0x560b380c41c1] ../src/gc/default/default.c:5821 ruby(gc_start) ../src/gc/default/default.c:6502 ruby(heap_prepare+0xa4) [0x560b380c4efc] ../src/gc/default/default.c:2074 ruby(heap_next_free_page) ../src/gc/default/default.c:2289 ruby(newobj_cache_miss) ../src/gc/default/default.c:2396 ruby(RB_SPECIAL_CONST_P+0x0) [0x560b380c5df4] ../src/gc/default/default.c:2420 ruby(RB_BUILTIN_TYPE) ../src/include/ruby/internal/value_type.h:184 ruby(newobj_init) ../src/gc/default/default.c:2136 ruby(rb_gc_impl_new_obj) ../src/gc/default/default.c:2500 ruby(newobj_of) ../src/gc.c:996 ruby(rb_imemo_new+0x37) [0x560b380d8bed] ../src/imemo.c:46 ruby(imemo_fields_new) ../src/imemo.c:105 ruby(rb_imemo_fields_new) ../src/imemo.c:120 ``` I have no reproduction, but my understanding based on the backtrace and error is that GC is triggered inside `newobj_init` causing the new object to be marked while in a incomplete state. I believe the fix is to pass the `shape_id` down to `newobj_init` so it can be set before the GC has a chance to trigger.
2025-12-03Rename `rb_obj_exivar_p` -> `rb_obj_gen_fields_p`Jean Boussier
The "EXIVAR" terminology has been replaced by "gen fields" AKA "generic fields". Exivar implies variable, but generic fields include more than just variables, e.g. `object_id`.
2025-12-03Handle NEWOBJ tracepoints settings fieldsJean Boussier
[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-01Speedup RBASIC_FIELDS_COUNT (#15273)Luke Gruber
We know the argument is not a class, module or special const, so we can skip these checks.
2025-11-26Eliminate redundant work and branching when marking T_OBJECT (#15274)Luke Gruber
2025-11-07renaming internal data structures and functions from namespace to boxSatoshi Tagomori
2025-10-21YJIT: ZJIT: Extract common bindings to jit.c and remove unnamed enums.Alan Wu
The type name bindgen picks for anonymous enums creates desync issues on the bindgen CI checks.
2025-08-29YJIT: getinstancevariable cache indexes for types other than T_OBJECTJean Boussier
While accessing the ivars of other types is too complicated to realistically generate the ASM for it, we can at least provide the ivar index as to not have to lookup the shape tree every time. ``` compare-ruby: ruby 3.5.0dev (2025-08-27T14:58:58Z merge-vm-setivar-d.. 5b749d8e53) +YJIT +PRISM [arm64-darwin24] built-ruby: ruby 3.5.0dev (2025-08-28T17:58:32Z yjit-get-exivar efaa8c9b09) +YJIT +PRISM [arm64-darwin24] | |compare-ruby|built-ruby| |:--------------------------|-----------:|---------:| |vm_ivar_get_on_obj | 930.458| 936.865| | | -| 1.01x| |vm_ivar_get_on_class | 134.471| 431.622| | | -| 3.21x| |vm_ivar_get_on_generic | 146.679| 284.408| | | -| 1.94x| ``` Co-Authored-By: Aaron Patterson <tenderlove@ruby-lang.org>
2025-08-27Replace ROBJECT_EMBED by ROBJECT_HEAPJean Boussier
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-26Ensure T_OBJECT and T_IMEMO/fields have identical layoutJean Boussier
2025-08-25Refactor rb_obj_ivar_set to delegate to obj_field_setJean Boussier
2025-08-25Get rid of rb_obj_set_shape_idJean Boussier
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-21Remove unused SPECIAL_CONST_SHAPE_IDÉtienne Barrié
Its usage was removed in 306d50811dd060d876d1eb364a0d5e6106f5e4f1.
2025-07-31Get rid of RSHAPE_PARENT in favor of RSHAPE_DIRECT_CHILD_PJean Boussier
`RSHAPE_PARENT` is error prone because it returns a raw untagged shape_id. To check if a shape is a direct parent of another, tags should be discarded. So providing a comparison function is better than exposing untagged ids.
2025-07-16YJIT: Side-exit on String#dup when it's not leaf (#13921)Takashi Kokubun
* YJIT: Side-exit on String#dup when it's not leaf * Use an enum instead of a macro for bindgen
2025-07-09Always use atomics to get the shape countJohn Hawthorn
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-04Remove unused src param from rb_shape_copy_fieldsJohn Hawthorn
2025-06-26variable.c: Refactor `generic_field_set` / `generic_ivar_set`Jean Boussier
These two functions are very similar, they can share most of their logic.
2025-06-24Cleanup and document `shape_id_t` layoutJean Boussier
2025-06-24Reduce exposure of FL_FREEZEJean Boussier
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-17Rename `imemo_class_fields` -> `imemo_fields`Jean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13626
2025-06-13Use the `shape_id` rather than `FL_EXIVAR`Jean Boussier
We still keep setting `FL_EXIVAR` so that `rb_shape_verify_consistency` can detect discrepancies. Notes: Merged: https://github.com/ruby/ruby/pull/13612
2025-06-13Enforce consistency between shape_id and FL_EXIVARJean Boussier
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. Notes: Merged: https://github.com/ruby/ruby/pull/13612
2025-06-13Add SHAPE_ID_HAS_IVAR_MASK for quick ivar checkJean Boussier
This allow checking if an object has ivars with just a shape_id mask. Notes: Merged: https://github.com/ruby/ruby/pull/13606
2025-06-13shape.c: cleanup unused IDsJean Boussier
id_frozen and id_t_object are no longer used. id_object_id no longer need to be exposed. Notes: Merged: https://github.com/ruby/ruby/pull/13605
2025-06-12Allocate `rb_shape_tree` staticallyJean Boussier
There is no point allocating it during init, it adds a useless indirection. Notes: Merged: https://github.com/ruby/ruby/pull/13596
2025-06-12Get rid of GET_SHAPE_TREE()Jean Boussier
It's a useless indirection. Notes: Merged: https://github.com/ruby/ruby/pull/13596
2025-06-12Get rid of `rb_shape_lookup`Jean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13596
2025-06-12shape.h: make RSHAPE static inlineJean Boussier
Since the shape_tree_ptr is `extern` it should be possible to fully inline `RSHAPE`. Notes: Merged: https://github.com/ruby/ruby/pull/13596
2025-06-12Turn `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
2025-06-11Refactor 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
2025-06-11shape.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
2025-06-07Simplify `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
2025-06-07Get rid of rb_shape_t.heap_idJean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13556
2025-06-07Get 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
2025-06-07Remove EMBEDDED shape_id flagsJean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13556
2025-06-07Leave the shape_id_t highest bit unused to avoid crashing YJITJean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13556
2025-06-07Replicate `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
2025-06-05Refactor raw accesses to rb_shape_t.capacityJean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/13524
2025-06-05Get 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
2025-06-04Get 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
2025-06-04vm_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
2025-06-04Get 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
2025-06-03Use 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
2025-06-02shape.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é <etienne.barrie@gmail.com> 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