Commit Graph
2563 Commits
Author SHA1 Message Date
Matt Valentine-House 132d22571b Add RUBY_ATOMIC_SIZE_LOAD
The size_t atomics had add, sub, cas, exchange and fetch_add but no
load, so the GC read its atomic size_t counters through the VALUE load
with a cast.

This commit adds RUBY_ATOMIC_SIZE_LOAD and rbimpl_atomic_size_load,
following rbimpl_atomic_load, and uses it for the deferred free count.
2026-10-23 18:51:09 +01:00
Nobuyoshi Nakada de04d82a87 Add conversions between rb_len_t and Fixnum 2026-10-21 23:55:00 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 db420d3ff5 Say 64-bit mswin where rb_len_t is 64 bits
SIZEOF_RB_LEN_T is 8 only on mswin64, so i386-mswin32 keeps long.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:07:39 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 ed11823184 Bump RUBY_ABI_VERSION
rb_len_t changes its width on mswin, and with it the layout of the lengths that extensions read through the public headers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:07:39 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 4e746b14fd Make rb_len_t 64 bits on mswin
long is 32 bits on mswin while pointers are 64 bits, so String, Array and MatchData could not reach 2GiB there. config.h now sets SIZEOF_RB_LEN_T to 8 on mswin64, and value.h then defines rb_len_t as int64_t. mingw still uses long.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:07:39 +09:00
Nobuyoshi Nakada 61261bf5c4 Add more assertions to RARRAY_AREF 2026-10-17 11:58:19 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 96fd3a3e1e Cast unsigned 64-bit pointers for the Interlocked functions
They take pointers to the signed LONG64. clang-cl warns about the difference in every file that includes ruby/atomic.h, as MSVC does at -W4 (C4057).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 13:39:04 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 dc6b65f0a7 Use direct threaded code with clang-cl
clang-cl supports labels as values and `__extension__`, but does not define __GNUC__, so the VM fell back to the switch dispatch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 13:39:04 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 7df6851cfc Define DEPRECATED_TYPE for clang-cl as for clang
clang-cl does not know `#pragma deprecated` and warns about it in every file that includes ruby.h. The warning is an error in mkmf checks with -WX.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 13:39:04 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 152394e6fb Use the Interlocked atomics whenever _MSC_VER is defined
clang-cl defines _MSC_VER but is not MSVC for RBIMPL_COMPILER_IS, so rbimpl_atomic_or and rbimpl_atomic_cas fell through to "Unsupported platform".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 13:39:04 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 b377234135 Add rb_len2long and rb_out_of_long
Like `rb_len2int`, `rb_len2long` narrows an `rb_len_t` with a range check, for extensions that keep a length in `long` and for intentional truncations where `rb_len_t` is wider than `long`. `rb_out_of_int` cannot be reused since its message names 'int'.

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 08:34:50 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 174639e092 Add HAVE_RB_LEN_T
An extension that also supports older versions can check it and fall back to `typedef long rb_len_t`, as with `HAVE_RB_IO_T`.

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 03:16:01 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 c4d16f7aee Accept SIZEOF_RB_LEN_T defined by the build
mkmf's check_sizeof('rb_len_t') defines SIZEOF_RB_LEN_T as a number, which redefined the macro with different tokens and warned, failing builds that treat warnings as errors. A static assert checks a given value against the type.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:00:15 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 5039d25b5a Add SIZEOF_RB_LEN_T
A typedef is invisible to the preprocessor, so an extension that also builds on older Ruby has no way to see whether `rb_len_t` exists or how wide it is. This gives it a macro to test before falling back to `typedef long rb_len_t`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:00:15 +09:00
Hiroshi SHIBATAandClaude Opus 5 cc3ba11012 Use rb_len_t in the C API for lengths and indices
Once rb_len_t widens this changes the `long *` output parameters of rb_range_beg_len(), rb_str_subpos(), rb_arithmetic_sequence_beg_len_step(), ruby_enc_find_basename() and ruby_enc_find_extname(), so extensions passing `long *` to them will need to be updated. The extension guides list these signatures verbatim and follow along.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-09 14:00:15 +09:00
Hiroshi SHIBATAandClaude Opus 5 123fce4e6a Use rb_len_t for lengths of RString, RArray and RMatch
These are the fields the length macros read, so they have to carry the type before anything built on those macros can follow. The layout stays as it is even once rb_len_t widens, because these fields are already padded to pointer alignment.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-09 14:00:15 +09:00
Hiroshi SHIBATAandClaude Opus 5 03e3376643 Add rb_len_t for lengths and indices of objects
`long` is 32-bit on LLP64 platforms such as Windows, while VALUE and pointers are 64-bit. Giving the lengths and indices of objects such as String and Array a type of their own is what lets a later change widen them there. The typedef is `long` on every platform for now and a static assert pins it that way, because the conversion macros, PRI_LEN_PREFIX and the width guards around them are all still spelled in terms of `long`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-09 14:00:15 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 b732b7d9f2 Avoid locked instructions for atomic loads on x64 Windows
An aligned load is atomic on x64, and seq_cst because stores here use xchg. The fallbacks issued lock xadd or lock cmpxchg on every load, which RUBY_VM_CHECK_INTS and inline cache reads pay for. ARM64EC also defines _M_X64, so it is excluded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 10:47:16 +09:00
Peter Zhu dbabf7d789 Remove ROBJECT_FIELDS macro in robject.h
The implementation of ROBJECT_FIELDS is defined in shape.h, which is not
public so ROBJECT_FIELDS can't be accessed publicly anyways.
2026-10-05 09:00:43 +09:00
Peter Zhu c6a042f7a4 Remove dead ROBJECT_EMBED_LEN_MAX macro 2026-10-03 10:14:43 +09:00
Peter Zhu a16ed993cf Remove dead ROBJECT_FIELDS_CAPACITY macro 2026-10-03 10:14:43 +09:00
Samuel Williams 5b6f593531 Introduce (internal) IO::Buffer::Storage and Slice. (#19186) 2026-10-03 10:46:24 +13:00
Samuel Williams 3c01c256ce Add IO::Buffer#advance. (#19122) 2026-10-02 14:58:52 +13:00
Peter Zhu 96d57e2403 Make rb_str_no_gvl_safe_acquire public C API
This commit renames rb_str_tmp_frozen_no_embed_acquire to rb_str_no_gvl_safe_acquire
and makes it part of the public C API.

There is currently no way for C extensions that use no GVL operations to
safely read from a string because it has no way of guaranteeing that the
string is not embedded. Embedded strings are not safe for no GVL operations
because GC compaction can run, which will mprotect the memory region and
will cause any read to SEGV.

See https://github.com/ruby/ruby/pull/9817 for when rb_str_tmp_frozen_no_embed_acquire
was introduced.
2026-10-01 10:02:46 +09:00
Jean Boussier 5c128f545b Deprecate RHASH_TBL
[Feature #22232]

Guaranteeing that any hash can be converted into an st_table is
limiting the evolution of RHash.

None of the public usages of `RHASH_TBL` were justified, they all
had equivalent `rb_hash_*` public APIs to perform the same thing
more efficiently without disabling write barriers nor coercing the
hash into an st_table.
2026-09-30 11:51:14 +02:00
Samuel Williams 1692691913 Make IO::Buffer slices offset-based so they survive source relocation. (#19090) 2026-09-28 19:16:19 +13:00
Hiroshi SHIBATAandClaude Opus 5.5 f49b514ce1 win32.h: Use stdint.h for intptr_t on mswin too
The fallback definitions were for Visual C++ 2008 and older, which had no stdint.h.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 12:42:26 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 62e374e9ef Fold MSVC version checks in the attribute detection headers
Every `RBIMPL_COMPILER_SINCE(MSVC, ...)` condition here holds for `_MSC_VER` 1915, the oldest version the headers accept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 12:42:26 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 c45c9c2674 Reject MSVC older than 1915 in the public headers
Building ruby needs `_MSC_VER` 1915 or later, but the generated config.h accepts 1910 and later for such a build, so an extension could still be compiled by 1910 through 1914.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 12:42:26 +09:00
Matt Valentine-House 2ad6b99a98 GC: scope rb_gc_register_address to the calling Ractor
The registered_globals list made every Ractor's GC scan every slot under
a shared lock. This commit splits it into per-Ractor lists.

We also maintain a global registry that references every Ractor that has
ever registered so that unregistering from a Ractor other than the one
that registered can look up the owning list.

When a Ractor is joined, the dead Ractor's slots are moved to the
joining Ractor's heap before the objspace merge happens.

This change tightens up the requirements for values stored in a
registered address.

Previously, Every Ractor's local GC scanned the shared list. So if a
slot held an unshareable object living in a different Ractor's heap,
that object was always kept alive regardless.

After this change, only the registering Ractor's GC scans its list. So if a
slot holds another Ractor's unshareable object, the owning Ractor's
local GC cannot see that reference, so it can collect the object while
the registered slot still points at it.

Storing such an object was already a Ractor containment violation. It
was just hidden by the shared scan.

[Feature #22277]
2026-09-25 19:24:10 +01:00
Hiroshi SHIBATAandClaude Opus 5 cf35145fc4 Reject a compiled program too big for its offset type
Concatenated large repeats reach a program past INT_MAX from a few hundred
kilobytes of source, and the offsets emitted into it wrap.  Cap the size
while the program is emitted, which does not depend on the length pass that
overflows along with it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-25 13:29:16 +09:00
Hiroshi SHIBATAandClaude Opus 5.5 36df189c2a Fix rbimpl_atomic_size_fetch_add on 32-bit Windows
It used InterlockedExchangeAdd64 on a 4-byte size_t, so the access also covered the following 4 bytes, which is the `tdata_unsafe_free_published` pointer for the caller in gc/default/default.c. Go through rb_atomic_t like the other size_t functions, which also fixes the missing return in the branch shared with 32-bit Solaris.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 08:55:09 +09:00
Harald Nordgren 5cd1287ff5 Prefer __has_include over HAVE_STDCKDINT_H for <stdckdint.h>
HAVE_STDCKDINT_H records what configure's compiler saw when ruby was
built.  __has_include asks the compiler that is compiling the header
right now.  When the two compilers are the same they always agree, so
checking __has_include first changes nothing.  They can only disagree
when the compiler is different, e.g. an extension built with an older
compiler that has no <stdckdint.h>.  Trusting the configure result then
means including a header that doesn't exist, which is a hard error.
Trusting __has_include falls back to __builtin_*_overflow, which works.

So only use HAVE_STDCKDINT_H when the compiler has no __has_include.
2026-09-25 08:34:23 +09:00
Nobuyoshi Nakada a323b13af9 Skip already frozen objects in RB_OBJ_FREEZE
Avoid calling `rb_obj_freeze_inline` for already frozen objects,
including immediate values, to match `rb_obj_freeze` semantics.
2026-09-19 18:51:41 +09:00
Nobuyoshi Nakada 92cef2802c Mark rb_freeze_singleton_class as internal
`rb_freeze_singleton_class` is an implementation detail of
`RB_OBJ_FREEZE`, so deprecate direct calls from extension libraries
before removing its public declaration in Ruby 4.2.
2026-09-19 18:51:40 +09:00
Nobuyoshi Nakada 4552e472c7 [DOC] Fix a typo 2026-09-18 23:17:09 +09:00
Nobuyoshi Nakada 85611dc266 [Bug #22324] APIs with observable side effects are not pure 2026-09-18 21:43:21 +09:00
Luke Gruber e755b92a3f Call dfree on non-thread-safe T_DATA with the VM barrier
When running multiple Ractors, we can't call dfree of a non-thread-safe
T_DATA while other Ractors are running or doing GC work. If there are multiple
Ractors, we save the T_DATA object's `dfree` and `data` pointer in an entry. Once
the entry buffer is full per-Ractor, we publish it to the global list atomically.
Once the threshold for these deferred T_DATAs is reached (right now ~65K), the next
Ractor to run interrupts calls the `dfree` functions for these objects under the VM
barrier. It does not do any other GC work during this postponed job.

If a global GC runs, it also calls the `dfree` functions for all these objects (it drains
the deferred-free queue). When only 1 Ractor is running (`rb_gc_single_objspace_p()`),
these objects are freed normally and aren't added to any queue.

NOTE
----
Embedded T_DATA objects need to be special-cased because their `data` points to inside the
object's slot itself, which we reuse right away now. For non-thread-safe T_DATA that is
embeddable, we need to create it as unembedded - even without Ractors.
2026-09-17 22:02:06 -04:00
Nobuyoshi Nakada b9d4fd7108 [Bug #22323] [DOC] Remove a stale internal note for typed data
Neither argument to `rb_typeddata_inherited_p` is intended to be NULL.
2026-09-17 13:01:17 +09:00
Samuel Williams aaf83bcebe Scope fiber_interrupt with an operation proxy. (#18793)
[Bug #21918]
2026-09-13 14:48:19 +12:00
Luke Gruber c329f36bea Add and use rb_gc_update_moved(VALUE *obj) which conditionally assigns
Using the `container->obj = rb_gc_location(container->obj)` pattern dirties pages unconditionally.
If we're in a forked process, this is bad for CoW. If the object hasn't moved, don't reassign.
2026-09-08 21:43:48 -04:00
Koichi SasadaandClaude Opus 5 a4c740449b ractor.h: export rb_obj_set_shareable()
RB_OBJ_SET_SHAREABLE() was unusable from extensions: the declaration
was outside RBIMPL_SYMBOL_EXPORT_BEGIN/END, so the symbol was compiled
with hidden visibility and did not appear in libruby.so.

Also document it, including the cost that a shareable object is not
collected by a local GC.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 01:30:01 +09:00
Samuel Williams 753ace46fe Lock IO::Buffer allocations during copy. (#18489) 2026-08-25 19:50:12 +12:00
Samuel Williams 44da9d7384 Make IO::Buffer I/O operations single-transfer and composable. (#18483) 2026-08-25 14:46:49 +12:00
Samuel Williams 53bc085645 Expose IO::Buffer mapping alignment. (#18474)
[Feature #21700]
2026-08-24 12:50:55 +00:00
Samuel Williams 09fdc3bed9 Avoid unsafe zero-length IO::Buffer operations. (#18465)
- All `null?` buffers will result in zero-length operations.
2026-08-24 09:06:28 +00:00
Samuel Williams c5a2c145c7 Make IO::Buffer locks reference counted. (#18429)
Share each lock count across a buffer and its slices so independent native operations retain the backing allocation until all users release it. Always acquire a lock for blocking I/O and protect each/each_byte callbacks from invalidating their backing pointers.
2026-08-22 16:43:18 +12:00
Nobuyoshi Nakada 21ed8de7fd Add fallbacks for __builtin_bswap128 and __builtin_memcpy 2026-08-19 16:10:36 +09:00
Jean Boussier cd070c053f st.c: swap types of entries_start and rebuilds_num
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.
2026-08-07 17:21:02 +02:00
Shugo MaedaandClaude Fable 5 9658933451 [Feature #9779] Add Module#descendants
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 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 23:05:57 +09:00