summaryrefslogtreecommitdiff
path: root/shape.h
AgeCommit message (Collapse)Author
2025-05-09Refactor `rb_shape_transition_frozen` to return a `shape_id`.Jean Boussier
Notes: Merged: https://.com/ruby/ruby/pull/13283
2025-05-09Get rid of useless SHAPE_MASKJean Boussier
Notes: Merged: https://.com/ruby/ruby/pull/13283
2025-05-09Rename `rb_shape_get_shape_by_id` -> `RSHAPE`Jean Boussier
Notes: Merged: https://.com/ruby/ruby/pull/13283
2025-05-09Refactor `rb_shape_get_next_iv_shape` to take and return ids.Jean Boussier
Notes: Merged: https://.com/ruby/ruby/pull/13283
2025-05-09Stop exposing rb_shape_get_root_shapeJean Boussier
Notes: Merged: https://.com/ruby/ruby/pull/13283
2025-05-09Remove unused rb_obj_debug_shapeJean Boussier
Notes: Merged: https://.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://.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://.com/ruby/ruby/pull/13283
2025-05-09Extract `rb_shape_free_all`Jean Boussier
Notes: Merged: https://.com/ruby/ruby/pull/13283
2025-05-08Move `object_id` in object fields.Jean Boussier
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 <[email protected]> Notes: Merged: https://.com/ruby/ruby/pull/13159
2025-05-08shape.c: refactor frozen shape to no longer be finalJean Boussier
This opens the door to store more informations in shapes, such as the `object_id` or object address in case it has been observed and the object has to be moved. Notes: Merged: https://.com/ruby/ruby/pull/13159
2025-05-08Refactor OBJ_TOO_COMPLEX_SHAPE_ID to not be referenced outside shape.hJean Boussier
Also refactor checks for `->type == SHAPE_OBJ_TOO_COMPLEX`. Notes: Merged: https://.com/ruby/ruby/pull/13159
2025-05-08Rename `ivptr` -> `fields`, `next_iv_index` -> `next_field_index`Jean Boussier
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`. Notes: Merged: https://.com/ruby/ruby/pull/13159
2025-05-05Make rb_shape.capacity an `attr_index_t`Jean Boussier
Notes: Merged: https://.com/ruby/ruby/pull/13257
2025-04-30Improve syntax style consistency in shape.c and shape.hJean Boussier
Most of this code use the `type * name` style, while the overwhemling majority of the rest of ruby use the `type *name` style. This is a cosmetic change, but helps with readability.
2024-10-03Rename size_pool -> heapMatt Valentine-House
Now that we've inlined the eden_heap into the size_pool, we should rename the size_pool to heap. So that Ruby contains multiple heaps, with different sized objects. The term heap as a collection of memory pages is more in memory management nomenclature, whereas size_pool was a name chosen out of necessity during the development of the Variable Width Allocation features of Ruby. The concept of size pools was introduced in order to facilitate different sized objects (other than the default 40 bytes). They wrapped the eden heap and the tomb heap, and some related state, and provided a reasonably simple way of duplicating all related concerns, to provide multiple pools that all shared the same structure but held different objects. Since then various changes have happend in Ruby's memory layout: * The concept of tomb heaps has been replaced by a global free pages list, with each page having it's slot size reconfigured at the point when it is resurrected * the eden heap has been inlined into the size pool itself, so that now the size pool directly controls the free_pages list, the sweeping page, the compaction cursor and the other state that was previously being managed by the eden heap. Now that there is no need for a heap wrapper, we should refer to the collection of pages containing Ruby objects as a heap again rather than a size pool Notes: Merged: https://.com/ruby/ruby/pull/11771
2024-06-04Do not emit shape transition warnings when YJIT is compilingJean Boussier
[Bug #20522] If `Warning.warn` is redefined in Ruby, emitting a warning would invoke Ruby code, which can't safely be done when YJIT is compiling.
2024-03-13Make special const and too complex shapes before T_OBJECT shapesPeter Zhu
2024-03-13Don't create per size pool shapes for non-T_OBJECTPeter Zhu
2024-02-23Remove unneeded RUBY_FUNC_EXPORTEDPeter Zhu
2023-12-04Use 32-bit integers for redblack_id_tPeter Zhu
On 32-bit systems, the shape cache size is 1048576 (value of REDBLACK_CACHE_SIZE), but a 16-bit unsigned integer can only go up to 65536. This means that the redblack_id_t can overflow and lead to a corrupted red-black tree. The following script crashes on 32-bit systems: o = Object.new 1_000_000.times do |i| o.instance_variable_set(:"@i#{i}", i) end
2023-11-20Don't try compacting ivars on Classes that are "too complex"Aaron Patterson
Too complex classes use a hash table to store ivs, and should always pin their IVs. We shouldn't touch those classes in compaction.
2023-11-17Refactor rb_obj_evacuate_ivs_to_hash_tableJean Boussier
That function is a bit too low level to called from multiple places. It's always used in tandem with `rb_shape_set_too_complex` and both have to know how the object is laid out to update the `iv_ptr`. So instead we can provide two higher level function: - `rb_obj_copy_ivs_to_hash_table` to prepare a `st_table` from an arbitrary oject. - `rb_obj_convert_to_too_complex` to assign the new `st_table` to the old object, and safely free the old `iv_ptr`. Unfortunately both can't be combined into one, because `rb_obj_copy_ivar` need `rb_obj_copy_ivs_to_hash_table` to copy from one object to another.
2023-11-13Revert "Revert "Remove SHAPE_CAPACITY_CHANGE shapes""Peter Zhu
This reverts commit 5f3fb4f4e397735783743fe52a7899b614bece20.
2023-11-10Revert "Remove SHAPE_CAPACITY_CHANGE shapes"Peter Zhu
This reverts commit f6910a61122931e4193bcc0fad18d839c319b720. We're seeing crashes in the test suite of Shopify's core monolith after this change.
2023-11-09Remove SHAPE_CAPACITY_CHANGE shapesPeter Zhu
We don't need to create a shape to transition capacity as we can transition the capacity when the capacity of the SHAPE_IVAR changes.
2023-11-08Refactor rb_shape_transition_shape_capa outJean Boussier
Right now the `rb_shape_get_next` shape caller need to first check if there is capacity left, and if not call `rb_shape_transition_shape_capa` before it can call `rb_shape_get_next`. And on each of these it needs to checks if we got a TOO_COMPLEX back. All this logic is duplicated in the interpreter, YJIT and RJIT. Instead we can have `rb_shape_get_next` do the capacity transition when needed. The caller can compare the old and new shapes capacity to know if resizing is needed. It also can check for TOO_COMPLEX only once.
2023-11-03vm_getivar: assume the cached shape_id like have a common ancestorJean Boussier
When an inline cache misses, it is very likely that the stale shape_id and the current instance shape_id have a close common ancestor. For example if the instance variable is sometimes frozen sometimes not, one of the two shape will be the direct parent of the other. Another pattern that commonly cause IC misses is "memoization", in such case the object will have a "base common shape" and then a number of close descendants. In addition, when we find a common ancestor, we store it in the inline cache instead of the current shape. This help prevent the cache from flip-flopping, ensuring the next lookup will be marginally faster and more generally avoid writing in memory too much. However, now that shapes have an ancestors index, we only check for a few ancestors before falling back to use the index. So overall this change speeds up what is assumed to be the more common case, but makes what is assumed to be the less common case a bit slower. ``` compare-ruby: ruby 3.3.0dev (2023-10-26T05:30:17Z master 701ca070b4) [arm64-darwin22] built-ruby: ruby 3.3.0dev (2023-10-26T09:25:09Z shapes_double_sear.. a723a85235) [arm64-darwin22] warming up...... | |compare-ruby|built-ruby| |:------------------------------------|-----------:|---------:| |vm_ivar_stable_shape | 11.672M| 11.679M| | | -| 1.00x| |vm_ivar_memoize_unstable_shape | 7.551M| 10.506M| | | -| 1.39x| |vm_ivar_memoize_unstable_shape_miss | 11.591M| 11.624M| | | -| 1.00x| |vm_ivar_unstable_undef | 9.037M| 7.981M| | | 1.13x| -| |vm_ivar_divergent_shape | 8.034M| 6.657M| | | 1.21x| -| |vm_ivar_divergent_shape_imbalanced | 10.471M| 9.231M| | | 1.13x| -| ``` Co-Authored-By: John Hawthorn <[email protected]>
2023-11-02Make every initial size pool shape a root shapePeter Zhu
This commit makes every initial size pool shape a root shape and assigns it a capacity of 0.
2023-11-01remove_instance_variable: Handle running out of shapesJean Boussier
`remove_shape_recursive` wasn't considering that if we run out of shapes, it might have to transition to SHAPE_TOO_COMPLEX. When this happens, we now return with an error and the caller initiates the evacuation.
2023-10-26Move some defines from shape.h to shape.cJean Boussier
If they are only used there, we might as well not expose them.
2023-10-24Remove SHAPE_MAX_NUM_IVSAaron Patterson
There is no longer a limit on the number of IVs you can store. SHAPE_MAX_NUM_IVS was used to work around the IV10K problem (the well known problem where setting 10k instance variables in a row would be too slow). The redblack tree works well at any shape depth, even depths greater than 80, and solves the IV10K problem.
2023-10-24`get_next_shape_internal` should always return a shapeAaron Patterson
If it runs out of shapes, or new variations aren't allowed, it will return "too complex"
2023-10-24geniv objects can become too complexAaron Patterson
2023-10-24remove IV limit / support complex shapes on classesAaron Patterson
2023-10-24increase the maximum number of ivsAaron Patterson
2023-10-24Use a functional red-black tree for indexing the shapesAaron Patterson
This is an experimental commit that uses a functional red-black tree to create an index of the ancestor shapes. It uses an Okasaki style functional red black tree: https://www.cs.tufts.edu/comp/150FP/archive/chris-okasaki/redblack99.pdf This tree is advantageous because: * It offers O(n log n) insertions and O(n log n) lookups. * It shares memory with previous "versions" of the tree When we insert a node in the tree, only the parts of the tree that need to be rebalanced are newly allocated. Parts of the tree that don't need to be rebalanced are not reallocated, so "new trees" are able to share memory with old trees. This is in contrast to a sorted set where we would have to duplicate the set, and also resort the set on each insertion. I've added a new stat to RubyVM.stat so we can understand how the red black tree increases.
2023-10-18Revert "shape.h: Make attr_index_t uint8_t"Katherine Oelsner
This reverts commit e3afc212ec059525fe4e5387b2a3be920ffe0f0e.
2023-10-11shape.h: Make attr_index_t uint8_tJean Boussier
Given `SHAPE_MAX_NUM_IVS 80`, we transition to TOO_COMPLEX way before we could overflow a 8bit counter. This reduce the size of `rb_shape_t` from 32B to 24B. If we decide to raise `SHAPE_MAX_NUM_IVS` we can always increase that type again.
2023-10-10Refactor rb_shape_transition_shape_capa to not accept capacityJean Boussier
This way the groth factor is encapsulated, which allows rb_shape_transition_shape_capa to be smarter about ideal sizes.
2023-04-16Move shape ID to flags for classes on 32 bitPeter Zhu
Moves shape ID to FL_USER4 to FL_USER19 for the shape ID on 32 bit systems. This makes the rb_classext_struct smaller so that it can be embedded. Notes: Merged: https://.com/ruby/ruby/pull/7719
2023-04-06Pull the shape tree out of the vm objectMatt Valentine-House
Notes: Merged: https://.com/ruby/ruby/pull/7393
2023-03-24Adjust SHAPE_BUFFER_SIZE with shape_id_tNobuyoshi Nakada
On platforms where `shape_id_t` is 16-bits, 0x80000 is out of range of this type. ``` ../src/shape.c: In function ‘shape_alloc’: ../src/shape.c:129:18: warning: comparison is always false due to limited range of data type [-Wtype-limits] 129 | if (shape_id == MAX_SHAPE_ID) { | ^~ ```
2023-03-22Make shape functions staticAaron Patterson
These functions don't need to be in the header file, we can declare them as static. Notes: Merged: https://.com/ruby/ruby/pull/7512
2023-03-22Fix shape allocation limitsAaron Patterson
We can only allocate enough shapes to fit in the shape buffer. MAX_SHAPE_ID was based on the theoretical maximum number of shapes we could have, not on the amount of memory we can actually consume. This commit changes the MAX_SHAPE_ID to be based on the amount of memory we're allowed to consume. Co-Authored-By: Jemma Issroff <[email protected]> Notes: Merged: https://.com/ruby/ruby/pull/7556
2023-03-20Use an st table for "too complex" objectsAaron Patterson
st tables will maintain insertion order so we can marshal dump / load objects with instance variables in the same order they were set on that particular instance [ruby-core:112926] [Bug #19535] Co-Authored-By: Jemma Issroff <[email protected]> Notes: Merged: https://.com/ruby/ruby/pull/7560
2023-03-06Stop exporting symbols for MJITTakashi Kokubun
Notes: Merged: https://.com/ruby/ruby/pull/7459
2023-02-21Bump SHAPE_MAX_NUM_IVS to 80 (#7344)Takashi Kokubun
Notes: Merged-By: k0kubun <[email protected]>
2023-02-06Limit maximum number of IVs on a shape on T_OBJECTSJemma Issroff
Create SHAPE_MAX_NUM_IVS (currently 50) and limit all shapes of T_OBJECTS to that number of IVs. When a shape with a T_OBJECT has more than 50 IVs, fall back to the obj_too_complex shape which uses hash lookup for ivs. Note that a previous version of this commit 78fcc9847a9db6d42c8c263154ec05903a370b6b was reverted in 88f2b94065be3fcd6769a3f132cfee8ecfb663b8 because it did not account for non-T_OBJECTS Notes: Merged: https://.com/ruby/ruby/pull/7188
2023-01-30Remove dead code in shapes.c and shapes.hPeter Zhu
Notes: Merged: https://.com/ruby/ruby/pull/7200