245 Commits

Author SHA1 Message Date
alpaca-tc
c8ddc0a843 Optimize callcache invalidation for refinements
Fixes [Bug #21201]

This change addresses a performance regression where defining methods
inside `refine` blocks caused severe slowdowns. The issue was due to
`rb_clear_all_refinement_method_cache()` triggering a full object
space scan via `rb_objspace_each_objects` to find and invalidate
affected callcaches, which is very inefficient.

To fix this, I introduce `vm->cc_refinement_table` to track
callcaches related to refinements. This allows us to invalidate
only the necessary callcaches without scanning the entire heap,
resulting in significant performance improvement.
2025-06-09 12:33:35 +09:00
Jean Boussier
0ea210d1ea Rename ivptr -> fields, next_iv_index -> next_field_index
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`.
2025-05-08 07:58:05 +02:00
Jean Boussier
87117756b5 st.c: Removed unused set_add_direct_with_hash function 2025-04-29 23:19:51 +02:00
Jean Boussier
c0417bd094 Use set_table to track const caches
Now that we have a `set_table` implementation, we can
use it to track const caches and save some memory.

We could even save some more memory if `numtable` didn't
store a copy of the `hash` and instead recomputed it every
time, but this is a quick win.
2025-04-26 12:10:32 +02:00
Jeremy Evans
e4f85bfc31 Implement Set as a core class
Set has been an autoloaded standard library since Ruby 3.2.
The standard library Set is less efficient than it could be, as it
uses Hash for storage, which stores unnecessary values for each key.

Implementation details:

* Core Set uses a modified version of `st_table`, named `set_table`.
  than `s/st_/set_/`, the main difference is that the stored records
  do not have values, making them 1/3 smaller. `st_table_entry` stores
  `hash`, `key`, and `record` (value), while `set_table_entry` only
  stores `hash` and `key`.  This results in large sets using ~33% less
  memory compared to stdlib Set.  For small sets, core Set uses 12% more
  memory (160 byte object slot and 64 malloc bytes, while stdlib set
  uses 40 for Set and 160 for Hash).  More memory is used because
  the set_table is embedded and 72 bytes in the object slot are
  currently wasted. Hopefully we can make this more efficient and have
  it stored in an 80 byte object slot in the future.

* All methods are implemented as cfuncs, except the pretty_print
  methods, which were moved to `lib/pp.rb` (which is where the
  pretty_print methods for other core classes are defined).  As is
  typical for core classes, internal calls call C functions and
  not Ruby methods.  For example, to check if something is a Set,
  `rb_obj_is_kind_of` is used, instead of calling `is_a?(Set)` on the
  related object.

* Almost all methods use the same algorithm that the pure-Ruby
  implementation used.  The exception is when calling `Set#divide` with a
  block with 2-arity.  The pure-Ruby method used tsort to implement this.
  I developed an algorithm that only allocates a single intermediate
  hash and does not need tsort.

* The `flatten_merge` protected method is no longer necessary, so it
  is not implemented (it could be).

* Similar to Hash/Array, subclasses of Set are no longer reflected in
  `inspect` output.

* RDoc from stdlib Set was moved to core Set, with minor updates.

This includes a comprehensive benchmark suite for all public Set
methods.  As you would expect, the native version is faster in the
vast majority of cases, and multiple times faster in many cases.
There are a few cases where it is significantly slower:

* Set.new with no arguments (~1.6x)
* Set#compare_by_identity for small sets (~1.3x)
* Set#clone for small sets (~1.5x)
* Set#dup for small sets (~1.7x)

These are slower as Set does not currently use the AR table
optimization that Hash does, so a new set_table is initialized for
each call.  I'm not sure it's worth the complexity to have an AR
table-like optimization for small sets (for hashes it makes sense,
as small hashes are used everywhere in Ruby).

The rbs and repl_type_completor bundled gems will need updates to
support core Set.  The pull request marks them as allowed failures.

This passes all set tests with no changes.  The following specs
needed modification:

* Modifying frozen set error message (changed for the better)
* `Set#divide` when passed a 2-arity block no longer yields the same
  object as both the first and second argument (this seems like an issue
  with the previous implementation).
* Set-like objects that override `is_a?` such that `is_a?(Set)` return
  `true` are no longer treated as Set instances.
* `Set.allocate.hash` is no longer the same as `nil.hash`
* `Set#join` no longer calls `Set#to_a` (it calls the underlying C
   function).
* `Set#flatten_merge` protected method is not implemented.

Previously, `set.rb` added a `SortedSet` autoload, which loads
`set/sorted_set.rb`.  This replaces the `Set` autoload in `prelude.rb`
with a `SortedSet` autoload, but I recommend removing it and
`set/sorted_set.rb`.

This moves `test/set/test_set.rb` to `test/ruby/test_set.rb`,
reflecting that switch to a core class.  This does not move the spec
files, as I'm not sure how they should be handled.

Internally, this uses the st_* types and functions as much as
possible, and only adds set_* types and functions as needed.
The underlying set_table implementation is stored in st.c, but
there is no public C-API for it, nor is there one planned, in
order to keep the ability to change the internals going forward.

For internal uses of st_table with Qtrue values, those can
probably be replaced with set_table.  To do that, include
internal/set_table.h.  To handle symbol visibility (rb_ prefix),
internal/set_table.h uses the same macro approach that
include/ruby/st.h uses.

The Set class (rb_cSet) and all methods are defined in set.c.
There isn't currently a C-API for the Set class, though C-API
functions can be added as needed going forward.

Implements [Feature #21216]

Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
Co-authored-by: Oliver Nutter <mrnoname1000@riseup.net>
2025-04-26 10:31:11 +09:00
John Hawthorn
443e2ec27d Replace tombstone when converting AR to ST hash
[Bug #21170]

st_table reserves -1 as a special hash value to indicate that an entry
has been deleted. So that that's a valid value to be returned from the
hash function, do_hash replaces -1 with 0 so that it is not mistaken for
the sentinel.

Previously, when upgrading an AR table to an ST table,
rb_st_add_direct_with_hash was used which did not perform the same
conversion, this could lead to a hash in a broken state where one if its
entries which was supposed to exist being marked as a tombstone.

The hash could then become further corrupted when the ST table required
resizing as the falsely tombstoned entry would be skipped but it would
be counted in num entries, leading to an uninitialized entry at index
15.

In most cases this will be really rare, unless using a very poorly
implemented custom hash function.

This also adds two debug assertions, one that st_add_direct_with_hash
does not receive the reserved hash value, and a second in
rebuild_table_with, which ensures that after we rebuild/compact a table
it contains the expected number of elements.

Co-authored-by: Alan Wu <alanwu@ruby-lang.org>
2025-03-05 14:05:24 -08:00
Peter Zhu
e0cb069c06 Remove dead rb_st_nth_key 2025-02-13 16:11:37 -05:00
Nobuyoshi Nakada
0923a98868
Move clean-up after table rebuilding
Suppress a false positive alert by CodeQL.
2024-02-09 11:09:56 +09:00
Peter Zhu
824ff48adc Move internal ST functions to internal/st.h
st_replace and st_init_existing_table_with_size are functions used
internally in Ruby and should not be publicly visible.
2023-12-25 10:41:12 -05:00
Koichi Sasada
7ba2506232 check modifcation whil ar->st
* delete `ar_try_convert` but use `ar_force_convert_table`
  to make program simple.
* `ar_force_convert_table` checks hash modification while
  calling `#hash` method with the following strategy:

1. copy keys (and vals) of ar_table
2. calc hashes from keys
3. check copied keys and hash's keys. if not matched, repeat from 1

fix [Bug #20050]
2023-12-15 11:58:43 +09:00
Nobuyoshi Nakada
9eac9d7178
[Bug #19969] Compact st_table after deleted if possible 2023-11-11 18:49:19 +09:00
jinroq
a70320b8cd Define NO_SANITIZE with reference to ext/bigdecimal/missing.c 2023-07-01 23:16:54 +09:00
jinroq
174dbe33cc Supress warning: ‘unsigned-integer-overflow’ attribute directive ignored [-Wattributes] 2023-07-01 23:16:54 +09:00
Peter Zhu
58386814a7 Don't check for null pointer in calls to free
According to the C99 specification section 7.20.3.2 paragraph 2:

> If ptr is a null pointer, no action occurs.

So we do not need to check that the pointer is a null pointer.
2023-06-30 09:13:31 -04:00
Peter Zhu
f0d08d11dc Fix memory leak when copying ST tables
st_copy allocates a st_table, which is not needed for hashes since it is
allocated by VWA and embedded, so this causes a memory leak.

The following script demonstrates the issue:

```ruby
20.times do
  100_000.times do
    {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9}
  end

  puts `ps -o rss= -p #{$$}`
end
```
2023-06-29 11:16:50 -04:00
Nobuyoshi Nakada
c94b5f121d De-duplicate parse_st.c code from st.c 2023-06-24 19:17:37 +09:00
Nobuyoshi Nakada
ba0bcc5203
Use ruby functions if RUBY is defined 2023-06-17 13:24:58 +09:00
Nobuyoshi Nakada
9001d54788
Expand #ifdef RUBY region
Include the functions which are only used for
`rb_hash_bulk_insert_into_st_table`.
2023-06-17 13:24:58 +09:00
Peter Zhu
0938964ba1 Implement Hash ST tables on VWA 2023-05-17 09:19:40 -04:00
Aaron Patterson
54dbd8bea8 Use an st table for "too complex" objects
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 <jemmaissroff@gmail.com>
2023-03-20 13:54:18 -07:00
Eric Wong
b9f90cafa1 st.c: spell `perturb' properly
Otherwise, a reader may wonder who `Peter B.' is and why
a variable is named after them...
2023-02-10 03:50:31 +00:00
Sergey Fedorov
567725ed30
Fix and improve coroutines for Darwin (macOS) ppc/ppc64. (#5975) 2022-10-19 23:49:45 +13:00
Peter Zhu
76bae60d9b [Bug #19038] Fix corruption of generic_iv_tbl when compacting
When the generic_iv_tbl is resized up, rebuild_table performs
allocations that can trigger GC. If autocompaction is enabled, then
moved objects are removed from and inserted into the generic_iv_tbl.
This may cause another call to rebuild_table to resize the
generic_iv_tbl. When returning back to the original rebuild_table, some
of the data may be stale, causing the generic_iv_tbl to be corrupted.

This commit changes rebuild_table to only read data from the st_table
after the allocations have completed.

Co-Authored-By: Matt Valentine-House <matt@eightbitraptor.com>
2022-10-06 09:01:12 -04:00
Takashi Kokubun
5b21e94beb Expand tabs [ci skip]
[Misc #18891]
2022-07-21 09:42:04 -07:00
Yusuke Endoh
1cb6790533 st.c: Fix a typo in a comment 2022-02-28 11:40:25 +09:00
Yusuke Endoh
496591de96 st.c: Do not clear entries_bound when calling Hash#shift for empty hash
tab->entries_bound is used to check if the bins are full in
rebuild_table_if_necessary.

Hash#shift against an empty hash assigned 0 to tab->entries_bound, but
didn't clear the bins. Thus, the table is not rebuilt even when the bins
are full. Attempting to add a new element into full-bin hash gets stuck.

This change stops clearing tab->entries_bound in Hash#shift.
[Bug #18578]
2022-02-10 00:14:27 +09:00
Nobuyoshi Nakada
e4f891ce8d
Adjust styles [ci skip]
* --braces-after-func-def-line
* --dont-cuddle-else
* --procnames-start-lines
* --space-after-for
* --space-after-if
* --space-after-while
2021-06-17 10:13:40 +09:00
tompng (tomoya ishida)
9f9045123e
st.c: skip all deleted entries [Bug #17779]
Update the start entry skipping all already deleted entries.
Fixes performance issue of `Hash#first` in a certain case.
2021-04-11 19:05:26 +09:00
Gannon McGibbon
9e0075a3d9 Replace "iff" with "if and only if"
iff means if and only if, but readers without that knowledge might
assume this to be a spelling mistake. To me, this seems like
exclusionary language that is unnecessary. Simply using "if and only if"
instead should suffice.
2021-01-19 12:06:45 -08:00
Nobuyoshi Nakada
7e1dbe5975
[DOC] Fixed st_udpate comment [ci skip]
Clarified that the first and second arguments to the callback
function are pointers to the KEY and the VALUE, but not those
values themselves.
2020-11-30 12:18:21 +09:00
Koichi Sasada
f6661f5085 sync RClass::ext::iv_index_tbl
iv_index_tbl manages instance variable indexes (ID -> index).
This data structure should be synchronized with other ractors
so introduce some VM locks.

This patch also introduced atomic ivar cache used by
set/getinlinecache instructions. To make updating ivar cache (IVC),
we changed iv_index_tbl data structure to manage (ID -> entry)
and an entry points serial and index. IVC points to this entry so
that cache update becomes atomically.
2020-10-17 08:18:04 +09:00
AGSaidi
511b55bcef
Enable arm64 optimizations that exist for power/x86 (#3393)
* Enable unaligned accesses on arm64

64-bit Arm platforms support unaligned accesses.

Running the string benchmarks this change improves performance
by an average of 1.04x, min .96x, max 1.21x, median 1.01x

* arm64 enable gc optimizations

Similar to x86 and powerpc optimizations.

|       |compare-ruby|built-ruby|
|:------|-----------:|---------:|
|hash1  |       0.225|     0.237|
|       |           -|     1.05x|
|hash2  |       0.110|     0.110|
|       |       1.00x|         -|

* vm_exec.c: improve performance for arm64

|                               |compare-ruby|built-ruby|
|:------------------------------|-----------:|---------:|
|vm_array                       |     26.501M|   27.959M|
|                               |           -|     1.06x|
|vm_attr_ivar                   |     21.606M|   31.429M|
|                               |           -|     1.45x|
|vm_attr_ivar_set               |     21.178M|   26.113M|
|                               |           -|     1.23x|
|vm_backtrace                   |       6.621|     6.668|
|                               |           -|     1.01x|
|vm_bigarray                    |     26.205M|   29.958M|
|                               |           -|     1.14x|
|vm_bighash                     |    504.155k|  479.306k|
|                               |       1.05x|         -|
|vm_block                       |     16.692M|   21.315M|
|                               |           -|     1.28x|
|block_handler_type_iseq        |       5.083|     7.004|
|                               |           -|     1.38x|
2020-08-14 02:15:54 +09:00
Nobuyoshi Nakada
33ca2d386b
Removed no longer used constants [Bug #16934]
`RESERVED_HASH_VAL` and `RESERVED_HASH_SUBSTITUTION_VAL` have not
been used directly in hash.c since 72825c35b0d8.
2020-06-04 17:00:52 +09:00
Nobuyoshi Nakada
0f2f07a9bb
Adjusted indents [ci skip] 2020-03-16 11:06:41 +09:00
K.Takata
e89ebdcb87
Fix typos (#2958)
* Fix a typo

* Fix typos in st.[ch]
2020-03-11 00:43:12 -07:00
Yusuke Endoh
1d81baf3c1 st.c: remove variables that are no longer used
to suppress a warning "variable 'check' set but not used"
2020-02-27 09:49:24 +09:00
卜部昌平
fbd7f08e92 kill ST_DEBUG [Bug #16521]
This compile-time option has been broken for years (at least since
commit 4663c224fa6c925ce54af32fd1c1cbac9508f5ec, according to git
bisect). Let's delete codes that no longer work.
2020-02-26 16:00:57 +09:00
卜部昌平
115fec062c more on NULL versus functions.
Function pointers are not void*.  See also
ce4ea956d24eab5089a143bba38126f2b11b55b6
8427fca49bd85205f5a8766292dd893f003c0e48
2020-02-07 14:24:19 +09:00
卜部昌平
5e22f873ed decouple internal.h headers
Saves comitters' daily life by avoid #include-ing everything from
internal.h to make each file do so instead.  This would significantly
speed up incremental builds.

We take the following inclusion order in this changeset:

1.  "ruby/config.h", where _GNU_SOURCE is defined (must be the very
    first thing among everything).
2.  RUBY_EXTCONF_H if any.
3.  Standard C headers, sorted alphabetically.
4.  Other system headers, maybe guarded by #ifdef
5.  Everything else, sorted alphabetically.

Exceptions are those win32-related headers, which tend not be self-
containing (headers have inclusion order dependencies).
2019-12-26 20:45:12 +09:00
Nobuyoshi Nakada
db16629008
Fixed misspellings
Fixed misspellings reported at [Bug #16437], only in ruby and rubyspec.
2019-12-20 09:32:42 +09:00
K.Takata
375124be51 st: Do error check only on non-Ruby 2019-10-21 11:14:36 +09:00
K.Takata
e70e81b54e st: Add NULL checking
These are found by Coverity.
2019-10-21 11:14:36 +09:00
Yusuke Endoh
5f35b8ca30
st.c: Use rb_st_* prefix instead of st_* (#2479)
The original st.c was public domain hash table implementation, but
Ruby's st.c is highly modified, and its data structure is not
compatiblie with the original one.

Therefore, when creating an extension library to wrap C code that uses
the original st.c, the symbols conflict, which leads to segfault.

This changes the prefix `st_*` of st.c functions to `rb_st_*` for
reflecting that they are specific to Ruby's, and avoid symbol conflicts.
2019-09-22 22:12:18 +09:00
Yusuke Endoh
2272efa463 st.c (st_add_direct_with_hash): make it "static inline"
It was originally static inline, but seemed to be accidentally published
at 8f675cdd00e2c5b5a0f143f5e508dbbafdb20ccd.
2019-09-22 16:39:47 +09:00
pavel
8e13da1ee8
optimize get_power2 [Feature #15631]
Merged: https://github.com/ruby/ruby/pull/2292
2019-08-28 11:29:49 +09:00
卜部昌平
78628618da struct st_hash_type now free from ANYARGS
After 5e86b005c0f2ef30df2f9906c7e2f3abefe286a2, I now think ANYARGS is
dangerous and should be extinct.  This commit adds function prototypes
for struct st_hash_type.  Honestly I don't understand why they were
commented out at the first place.
2019-08-27 15:52:26 +09:00
卜部昌平
6dd60cf114 st_foreach now free from ANYARGS
After 5e86b005c0f2ef30df2f9906c7e2f3abefe286a2, I now think ANYARGS is
dangerous and should be extinct.  This commit deletes ANYARGS from
st_foreach.  I strongly believe that this commit should have had come
with b0af0592fdd9e9d4e4b863fde006d67ccefeac21, which added extra
parameter to st_foreach callbacks.
2019-08-27 15:52:26 +09:00
tenderlove
91793b8967 Add GC.compact again.
🙏

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@67620 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2019-04-20 01:19:47 +00:00
tenderlove
744e5df715 Reverting compaction for now
For some reason symbols (or classes) are being overridden in trunk

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@67598 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2019-04-17 09:41:41 +00:00
tenderlove
3c55b643ae Adding GC.compact and compacting GC support.
This commit adds the new method `GC.compact` and compacting GC support.
Please see this issue for caveats:

  https://bugs.ruby-lang.org/issues/15626

[Feature #15626]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@67576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2019-04-17 03:17:25 +00:00