summaryrefslogtreecommitdiff
path: root/shape.c
AgeCommit message (Collapse)Author
6 hoursImprove 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-12-24[DOC] Hide `RubyVM::Shape` that is for debug from RDoc totallyNobuyoshi Nakada
2024-11-21Annotate anonymous mmapKunshan Wang
Use PR_SET_VMA_ANON_NAME to set human-readable names for anonymous virtual memory areas mapped by `mmap()` when compiled and run on Linux 5.17 or higher. This makes it convenient for developers to debug mmap. Notes: Merged: https://github.com/ruby/ruby/pull/12119
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://github.com/ruby/ruby/pull/11771
2024-08-16Parenthesize macro argumentsNobuyoshi Nakada
Notes: Merged: https://github.com/ruby/ruby/pull/11389
2024-08-16Simplify and clarify bitmask calculationNobuyoshi Nakada
Notes: Merged: https://github.com/ruby/ruby/pull/11389
2024-08-16Fix some warningsRaed Rizqie
* Fix unused functions when no `mmap`. ``` shape.c:285:1: warning: unused function 'redblack_insert' [-Wunused-function] 285 | redblack_insert(redblack_node_t * tree, ID key, rb_shape_t * value) | ^~~~~~~~~~~~~~~ ``` * Fix unknown warning group '-Wmaybe-uninitialized' with clang. ``` thread_win32.c:596:1: warning: unknown warning group '-Wmaybe-uninitialized', ignored [-Wunknown-warning-option] 596 | COMPILER_WARNING_IGNORED(-Wmaybe-uninitialized) | ^ ``` Co-authored-by: Nobuyoshi Nakada <nobu.nakada@gmail.com> Notes: Merged: https://github.com/ruby/ruby/pull/11376 Merged-By: nobu <nobu@ruby-lang.org>
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-05-09`redblack_cache_ancestors` is enabled only when `mmap` is availableNobuyoshi Nakada
2024-04-25Use xcalloc for allocating shape treePeter Zhu
The GC is initialized by this point, so we can use xcalloc instead of ruby_mimcalloc.
2024-04-24Add ruby_mimcallocPeter Zhu
Many places call ruby_mimmalloc then MEMZERO. This can be reduced by using ruby_mimcalloc instead.
2024-03-30If we have a shape cache we should use itAaron Patterson
If there is a shape cache, then we should believe the results instead of doing a linear search for non-existent items This fixes a case where checking the index of an undefined ivar would result in an O(n) search. Now we get O(log n). Benchmark is as follows: ```ruby N = ARGV[0].to_i class ManyIVs class_eval "def initialize;" + N.times.map { "@a#{_1} = #{_1}" }.join("\n") + "end" def check defined?(@not) end end class Subclass < ManyIVs def initialize super @foo = 123 end end def t s = Process.clock_gettime Process::CLOCK_MONOTONIC yield Process.clock_gettime(Process::CLOCK_MONOTONIC) - s end def test a = ManyIVs.new b = Subclass.new t { 200000.times { a.check; b.check } } end puts "#{N},#{test}" ``` On the master branch: ``` $ for i in (seq 1 3 32); ./miniruby test.rb $i; end 1,0.015619999991031364 4,0.013061000005109236 7,0.013365999999223277 10,0.015474999992875382 13,0.017674999980954453 16,0.020055999979376793 19,0.02260500000556931 22,0.0254080000158865 25,0.02806599999894388 28,0.031244999991031364 31,0.034568000002764165 ``` On this branch: ``` $ for i in (seq 1 3 32); ./miniruby test.rb $i; end 1,0.015848999988520518 4,0.013225000002421439 7,0.013049000001046807 10,0.010697999998228624 13,0.010902000009082258 16,0.011448000004747882 19,0.01151199999731034 22,0.011539999977685511 25,0.01173300002119504 28,0.011900000012246892 31,0.012278999987756833 ```
2024-03-13Remove unused size_pool_edge_namesPeter Zhu
2024-03-13Don't allow SHAPE_T_OBJECT in rb_shape_alloc_new_childPeter Zhu
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-03-13Don't directly read the SIZE_POOL_COUNT in shapesPeter Zhu
This removes the assumption about SIZE_POOL_COUNT for shapes.
2024-02-23Remove unneeded RUBY_FUNC_EXPORTEDPeter Zhu
2024-01-12Handle mmap failures for redblack tree cacheAaron Patterson
The redblack tree cache is totally optional, so if we can't allocate room for the cache, then just pretend as if the cache is full if mmap fails
2023-12-20Fix a grammar issue in the shape performance warning messageJean Boussier
2023-12-18Use #initialize instead of `initialize` in shape perf warningJean Boussier
This is more consistent with other messages.
2023-12-18[DOC] No document for internal or debug methodsNobuyoshi Nakada
2023-12-18Make the SHAPE_TOO_COMPLEX performance warning more actionableJean Boussier
As suggested by Mame, we should try to help users fix the issues without having to lookup the meaning of the warning.
2023-12-06Re-embed when removing Object instance variablesPeter Zhu
Objects with the same shape must always have the same "embeddedness" (either embedded or heap allocated) because YJIT assumes so. However, using remove_instance_variable, it's possible that some objects are embedded and some are heap allocated because it does not re-embed heap allocated objects. This commit changes remove_instance_variable to re-embed Object instance variables when it becomes small enough.
2023-12-06Deduplicate assertions in redblack_balancePeter Zhu
The bug in i686 was fixed in commit 71babe5536bdb2238509752d8706194ee57ff485.
2023-12-05Fix alphabetical order of include in shape.cPeter Zhu
2023-12-01Add assertions for shape cache grandchild nodesPeter Zhu
2023-11-30Add assertions in redblack_balancePeter Zhu
These assertions check that binary search tree invariants are held for the new tree.
2023-11-30Rename variables redblack_balancePeter Zhu
It's too difficult for me to keep track that y is the new node, x is the new left node, z is the new right node, a is the new left left node, b is the new left right node, c is the new right left node, and d is the new right right node. This commit refactors the variable names to be more descriptive.
2023-11-29Assert that the left and right nodes are correctPeter Zhu
2023-11-28Assert node inserted into red-black tree existsPeter Zhu
2023-11-27Add assertions to check created red-black treePeter Zhu
2023-11-27Fix indentation in comment in shape.cPeter Zhu
2023-11-25Verify correctness of shape cachePeter Zhu
This commit adds assertions to verify that the shape cache is correct compared to the shape tree.
2023-11-25Verify that duplicate shape is not createdPeter Zhu
This adds an assertion that the instance variable does not already exist in the shape tree when creating a new shape.
2023-11-22Fix off-by-one with RubyVM::Shape.exhaust_shapesAlan Wu
Previously, the method left one shape available (MAX_SHAPE_ID) when called without arguments.
2023-11-22Speedup test_shape.rbJean Boussier
Many tests start by exhausting all shapes, which is a slow process. By exposing a method to directly move the bump allocator forward we cut test runtime in half. Before: ``` Finished tests in 1.544756s ``` After: ``` Finished tests in 0.759733s, ```
2023-11-17Fix corruption when out of shape during ivar removePeter Zhu
Reproduction script: ``` o = Object.new 10.times { |i| o.instance_variable_set(:"@a#{i}", i) } i = 0 a = Object.new while RubyVM::Shape.shapes_available > 2 a.instance_variable_set(:"@i#{i}", 1) i += 1 end o.remove_instance_variable(:@a0) puts o.instance_variable_get(:@a1) ``` Before this patch, it would incorrectly output `2` and now it correctly outputs `1`.
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-13Don't overwrite shape capacity when removing ivarPeter Zhu
Other objects may be using the shape, so we can't change the capacity otherwise the other objects may have a buffer overflow.
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 <john@hawthorn.email>
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-02Better handle running out of shapes in remove_shape_recursiveJean Boussier
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-31Add ST table to gen_ivtbl for complex shapesPeter Zhu
On 32-bit systems, we must store the shape ID in the gen_ivtbl to not lose the shape. If we directly store the ST table into the generic ivar table, then we lose the shape. This makes it impossible to determine the shape of the object and whether it is too complex or not.
2023-10-31Handle running out of shapes in `Object#dup`Jean Boussier
There is a handful of call sites where we may transition to OBJ_TOO_COMPLEX_SHAPE if we just ran out of shapes, but that weren't handling it properly.
close