A char is more than large enough for counting rebuilds, and it's
fine if it rolls over.
The table being rebuilt exactly 255 times between two check seems
impossible.
On the other hand, if `Hash#shift` is abused, `entries_start` is
more likely to reach MAX_UCHAR.
So swapping the two members is preferable.
Module#descendants returns an array of classes and modules that have
the receiver in their ancestors; it is the inverse of Module#ancestors.
The receiver itself, singleton classes, and refinements are not included.
Co-Authored-By: Claude Fable 5 <[email protected]>
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
[Feature #22222]
This allows to efficiently load iseq from mmaped files and other
buffers without having to copy the bytes into a Ruby string an
then invoke `RubyVM::InstructionSequence.load_from_binary`.
This allows `st_table + RHash` to fit in a `64B` slot.
It is achieved by turning `entries_start` from pointer size
down to a single byte.
This means it can now overflow, if you delete the first element
255 times, but in such case we can rebuild the table entirely,
which is an acceptable tradeoff.
The same change is applied to `set_table`, but mostly for consistency,
as another 8B would need to be reclaimed for `Set` to fit in 64B slots.
Instead of spilling into a raw buffer, `RObject` now spills
into an `IMEMO/fields` object like other types.
From an instance variable layout standpoint, an extended `RObject`
is now identical to a `RTypedData`, as in they both store the
reference to their `IMEMO/fields` at the same offset (`VALUE * 2`).
One positive consequence of this is that the only case where a `T_OBJECT`
needs sweeping is if a finalizer was registered.
YJIT now side exit when it need to write a new ivar into a `RObject`
that is out of space. This is unlikely to cause a performance regression
as this codepath isn't supposed to happen after warmup given `max_iv_count`
is recorded on classes, so future objects should be large enough.
Hence it's best not to waste executable memory for such codepath.
ZJIT lost support for writting into extended `RObject`.
Most of the code to support it is there it's just missing an
implementation of `RBASIC_SET_SHAPE_ID`, which recently changed
to strip some bits out of the shape (see comments).
I will leave it to the ZJIT team to implement it (sorry).
There are a few future cleanups planned that I keep for followups:
- We can now get rid of the `ROBJECT_HEAP` flag, it's redundant with
the shape layout bits.
- `imemo_fields` can now embed the `st_table` when complex.
Co-Authored-By: John Hawthorn <[email protected]>
Co-authored-by: Randy Stauner <[email protected]>
The implementation was removed together with Class#descendants in
3bd5f27f73 ([Feature #14394]), but the
declaration was left behind.
Co-Authored-By: Claude Fable 5 <[email protected]>
Followup: https://github.com/ruby/ruby/pull/17671
[Bug #22184]
`onigmo.h` contains a lot of declarations that can easily
conflict with third party code, hence it's better to keep
it opaque. That however requires a few hacks.
When embeddeding `struct re_pattern_buffer`, `RRegexp` end up
488B large, which result in a rather minimal 24B waste in 512B slots.
This however requires a few changes:
- Stop relying on `RREGEXP_PTR == NULL` to check for initialization.
- `reg_copy` requires a new `onig_reg_copy_body` API.
Commit 0ea210d renamed ROBJECT_IVPTR to ROBJECT_FIELDS, so it would have
caused compatibility issues anyways. Since there has been no issues, it
means that nobody is using it. We can make this dangerous API private since
no C extension should be using it anyways.
Lets a TypedData type declare its dfree as thread-safe, so the GC may
run it on any thread, in parallel, and concurrently with Ruby code.
Implies RUBY_TYPED_FREE_IMMEDIATELY.
By moving the `rb_intern` to the caller, we allow compilers to
precompute the `strlen` part of `rb_intern` which isn't a huge win,
but happens quite a lot as part of Ruby's boot process and when
requiring native gems.
By inlining the `rb_intern()` call, we allow it to be replaced
by `rb_intern_const()` which with most compiler will allow to
save the `strlen` call when invoked with a string literal.
This is a small optimization, but during program boot, `rb_define_method`
is called thousands of times.
Other `rb_define_*` function could benefit from the same treatment,
but that require exposing an `_id` versionm, which most of them lack.
In many place ALLOC_V / ALLOCV_N is used as a safer `alloca`,
and to behave like stack memory, `ALLOCV` does scan its buffer
for references using `rb_gc_mark_locations`.
The problem is that it's quite slow, and in many cases, the
temporary buffer is known not to contain any references.
e.g. `ALLOCV_N(uint32_t, buf0, len)` can't possibly contain references,
as the element size is too small.
Prior to a26f528b3b, `rbimpl_rtypeddata_p`
checked whether a flag that is no longer used since that commit was set.
As a result, typed data objects created in newer versions of Ruby are
considered as untyped in extension libraries compiled with older headers.
This allows us to treat the two types of T_DATA the same way when
reading instance variables.
Non-TypedData T_DATA are deprecated, so making them faster isn't
particularly important, but it is helpful to avoid needing to test for
TypedData and adding another special case.
Same optimization that was applied to `set_table` in
85c52079aa
This saves one pointer per `st_table`.
Now that GC support 64B slots, if we can save another 8B
either in `st_table` or in `struct RHash`, hashes would now
fit in 64B slots.
That API made sense before b00f280d4b
as finding a module name was costly, but it now is a very cheap
operation, and that function is now just an outdated alias.
Move rb_int_parse_cstr() declaration and RB_INT_PARSE_* flags from
internal/bignum.h to the public header include/ruby/internal/intern/bignum.h
so that C extensions can use this function without writing their own
prototype declarations.
The flags are changed from an enum to #define macros to follow the
convention used in the public header for similar constants.