Keep the core dependency generation rule in `depend` so configure and
Windows setup share the same entry point. Preserve NMake output when
the generated dependency file is rebuilt.
Generate only core and encoding dependencies during configure.
Generate extension dependency files from `configure-ext.mk` after
`miniruby` is available, so `THREAD_MODEL` can be resolved before
rules enter an extension Makefile.
Select the extension scope when `-extensions` is passed. Keep quoted
project-internal headers ahead of similarly named public headers while
scanning extension sources. Limit snapshot expansion to files needed
before `miniruby`.
Use depends declarations for emitted dependency names instead of
overloading generated declarations or rewriting thread headers in
code. This keeps scanning, generation, and dependency expansion
separate and makes platform-selected thread dependencies explicit.
Move fixed preprocessor macro handling into dependency declarations so
the scan inputs and emitted dependencies are visible in depend files.
Add source-specific define and undef declarations for `parse.y` and
`ripper.y`.
Replace `tool/update-deps` with a Ruby source scanner so dependency
updates no longer require GNU make, a configured build, or compiler
preprocessor output.
Keep compact source mappings and scanner declarations in dependency
files, and expand complete rules into the build directory. Avoid the
temporary fixture headers required by the compiler-driven prototype.
Use the generated rules from GNU make, BSD make, and NMake builds.
Support out-of-tree and read-only source trees, and retain expanded
dependencies shipped in release archives when baseruby is unavailable.
rb_require_string delegates requires from non-main Ractors to the
main Ractor via rb_ractor_require, so the main-Ractor guard here was
unnecessary. Drop it and claim the load with an atomic exchange,
because Ractors run in parallel and the plain bool flag was only safe
under that guard. did_you_mean already keeps its state Ractor-safe,
so suggestions now appear in non-main Ractors as well.
Suggested by John Hawthorn.
[Feature #21951]
Defer loading these gems from boot to the first error display. They
only decorate Exception#detailed_message, so requiring them at boot is
unnecessary overhead. `ruby -e1` with user-installed gems drops from
114.3ms to 30.2ms on Apple M1 Pro, matching the --disable-* flags for
the three gems.
exc_detailed_message forces the autoload entries once on the first
call, only in the main Ractor, and then re-dispatches to pick up the
detailed_message decorators the gems prepend. When the first call
arrives through an already-prepended decorator, re-dispatching is
skipped to avoid decorating twice. The gems are loaded with the
C-level require so that displaying an error neither invokes nor
depends on Kernel#require monkeypatches.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The empty modules existed only as feature flags for gem_prelude to
require the gems at boot. Autoload entries serve the same flag role
and also load the gems on direct constant access. gem_prelude now
requires 'syntax_suggest' itself, which only loads core_ext, so that
the eager require does not trigger the autoload circularly.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Followup: https://github.com/ruby/ruby/pull/17631
Now that complex `RObject` always have an IMEMO/fields, we no
longer need to have an external `st_table` to replicate the
memory layout of `RObject`.
Registering an exit handler with Kernel#at_exit or END{} in a non-main
Ractor behaved confusingly: the block ran in the main Ractor at process
exit even though it was registered from another Ractor. Raise
Ractor::IsolationError instead.
[Feature #22139]
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit implements support in ZJIT for inlining GC fast path. The GC
fast path is defined in gc_fastpath.rs for both the default GC and MMTk.
For the default GC, the fast path uses the bump pointer allocator that
was implemented in https://github.com/ruby/ruby/pull/17201. If the bump
pointer region is full, it will bail out and fall back to the slow path.
This GC fast path is used by the newarray instruction in ZJIT in the empty
array case. We can see significant improvements in the following microbenchmark,
which allocates 100 million empty arrays:
def run(max)
i = 0
while i < max
a = []
i += 1
end
end
30.times { run(2) }
run(100_000_000)
This microbenchmark runs 1.5x faster on my machine:
Benchmark 1: master
Time (mean ± σ): 583.3 ms ± 10.1 ms [User: 569.3 ms, System: 12.0 ms]
Range (min … max): 571.9 ms … 600.0 ms 10 runs
Benchmark 2: branch
Time (mean ± σ): 389.5 ms ± 8.2 ms [User: 375.0 ms, System: 12.1 ms]
Range (min … max): 380.2 ms … 405.3 ms 10 runs
Summary
branch ran
1.50 ± 0.04 times faster than master
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.
concurrent_set.c now includes ruby/ractor.h for RB_OBJ_SET_SHAREABLE.
(id_table.c is #included into symbol.c, which already depends on ruby/ractor.h,
so no separate entry is needed.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Get rid of the CFUNC overhead in String#ascii_only? and #valid_encoding?. Define them as leaf Primitive.cexpr! builtins in a new string.rb, following the pattern of numeric.rb.
This makes them 1.2x-1.4x faster across the interpreter, YJIT, and
ZJIT.
Move ZJIT's cfunc annotation for String#ascii_only? to annotate_builtin!, and add one for String#valid_encoding?.
Fix CI for builtin String#ascii_only?
When every element is a String sharing one ASCII-compatible fast-path
encoding (UTF-8/US-ASCII/ASCII-8BIT) and the separator is compatible, build
the result with a single memcpy pass instead of appending element by element
through rb_str_buf_append. Other cases fall back to the existing path.
* Reserve 2 bits for expressing object layout
We would like to make instance variable reads in the JIT compiler faster
(as well as simplify the JIT implementation). Currently, in order to
read an instance variable, we have to:
1. Test for heap object
2. Load object to a 64 bit register
3. Mask the object header
4. Bit test against the masked header
5. JNE
6. Load field
We would like to:
1. Test for heap object
2. Load object shape to a 32 bit register
3. Bit test against the shape
4. JNE
5. Load field
The way we fetch instance variables is not consistent across objects.
In order to realize our goal, we need to encode object layout inside the
shape. If we encode object layout inside the shape, then the shape
itself will guarantee that the access pattern generated by the JIT
compiler is correct.
We should encode the following load patterns into the shape tag bits.
This way we can share shapes on transitions, but be able to
differentiate the access patterns for the JIT compiler. In other words,
two objects can have an `@a -> @b -> @c` transition and share the same
shape, but the tag bits can differentiate the access pattern so that the
JIT compiler can be confident that the machine code is correct.
Here are the patterns:
1. Embedded/Extended T_OBJECT Instance Variables
Objects with direct references to instance variables or via malloc
buffer
2. Objects with fields_objects fields
These are Data and TypedData objects. They have an associated axillary
imemo/fields object that stores the instance variables. The access
pattern is `object[2] + 2`. The fields object is the 3rd field, and the
instance variables start at +2 inside the fields object. The fields
object itself is a Ruby object, so it contains the usual header bits +
class headers.
3. Non Boxable Classes / Modules
This is similar to Objects with fields_objects, but the fields object is
stored at a different offset. We’re differentiating this from boxable
classes and modules because those are harder to support.
4. Other
"Other" pattern is for objects that are rare, or have
difficult-to-implement access patterns. This includes:
* Boxable classes and modules
* Structs (for now)
* Objects that use the geniv table
Proposed shape bit layout:
```
Current shape_id_t is 32 bits:
31 28 27 26 25 24 23 22 19 18 0
+-----------+--+--+--+--+--+------------+----------------------------+
| unused |L1|L0|OI|FR|CX| heap index | shape tree offset |
+-----------+--+--+--+--+--+------------+----------------------------+
| | | | | | |
| | | | | | +-- bits 0-18: SHAPE_ID_OFFSET_MASK
| | | | | +--------------- bits 19-22: SHAPE_ID_HEAP_INDEX_MASK
| | | | +------------------ bit 23: SHAPE_ID_FL_COMPLEX
| | | +--------------------- bit 24: SHAPE_ID_FL_FROZEN
| | +------------------------ bit 25: SHAPE_ID_FL_HAS_OBJECT_ID
+--+--------------------------- bits 26-27: SHAPE_ID_LAYOUT_MASK
```
The important part about these layout patterns is that they do not
reflect the _type_ of object, only how the object is laid out in memory.
For example, we currently treat structs as "other", but we can refactor
them to have the same layout as "Objects with fields_objects", and when
we do that they should get a different bit in the shape header.
This commit only reserves the two bits, it doesn't use them in the JIT
compiler yet.
Co-Authored-By: John Hawthorn <john@hawthorn.email>
Co-Authored-By: Max Bernstein <tekknolagi@gmail.com>
* Update gc.c
Co-authored-by: Nobuyoshi Nakada <nobu.nakada@gmail.com>
* Update shape.h
Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
* fix function name
* Update shape.c
Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
* fix function name
* Revert "Update shape.c"
This reverts commit 900711defc6c541a93f3393a350819ae88cf87f1.
* add comment
---------
Co-authored-by: John Hawthorn <john@hawthorn.email>
Co-authored-by: Max Bernstein <tekknolagi@gmail.com>
Co-authored-by: Nobuyoshi Nakada <nobu.nakada@gmail.com>
Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
This change separates the master box from the root box, as the single
master copy of boxes.
Before this change, the root box is the source of copies, and also
it runs builtin classes' code. Builtin code makes changes by
requiring files, thus the source of copies is mutable, be different
from the past one. This causes different internal states of boxes,
depending on when it is created.
After this change, all boxes are created from the master box, and
the master box never runs code, so it realizes the immutable source
of copies.
This also makes is possible to separate RubyGems (and other default
gems) from each boxes. All boxes will have their own copies of RubyGems.
RubyGems has its internal state, but it'll be separated between boxes
after this change.
These are internal-only helpers which can be used instead of the
RMATCH_REGS struct directly. RMATCH_REGS is just a pointer offset from
the RMatch VALUE itself, so this should not significantly affect
codegen.
The motivation for this is that it's both simpler, and should move us
towards being able to replace the storage for RMATCH, and to be able to
store the positions embedded instead of in separate malloc memory.
[Bug #21818]
Currently exceptions can be sent across ractors,
but because of a limitation in the TypedData API,
the exception backtrace is duped as an empty backtrace.
The problem is that backtraces are embedded objects,
hence the classic `rb_class_alloc(klass)` API is insufficient
because we need to know the size of the Backtrace object we're
duping to instantiate the copy.
This is worked around by changing Ractors to call `#clone` on objects
rather than use `rb_obj_clone`, and to implement `Thread::Backtrace#clone`
to properly clone the variable size object.
Add rb_iseq_bare_opcode_at_pc which uses rb_vm_insn_addr2insn to
return the base instruction, stripping trace/zjit variants. Use it
in iseq_may_write_block_code to simplify the match arms.
* Instances of a subclass of Regexp are not frozen for compatibility.
* [Feature #8948]
* Use a less confusing example in test_regexp2,
the ivar was named @encoding but had no effect on Regexp#encoding.