<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ruby.git/yjit.h, branch v4.0.3</title>
<subtitle>The Ruby Programming Language</subtitle>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/'/>
<entry>
<title>ZJIT: Add --zjit-stats (#14034)</title>
<updated>2025-07-29T17:00:15+00:00</updated>
<author>
<name>Takashi Kokubun</name>
<email>takashikkbn@gmail.com</email>
</author>
<published>2025-07-29T17:00:15+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=b22eb0e468a88d2da77cecf2355623fe7eff1ba6'/>
<id>b22eb0e468a88d2da77cecf2355623fe7eff1ba6</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>YJIT: Set code mem permissions in bulk</title>
<updated>2025-07-14T20:21:55+00:00</updated>
<author>
<name>Kunshan Wang</name>
<email>wks1986@gmail.com</email>
</author>
<published>2025-06-30T06:21:30+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=51a3ea5adeb452e51c119a395acfd5c87cc63735'/>
<id>51a3ea5adeb452e51c119a395acfd5c87cc63735</id>
<content type='text'>
Some GC modules, notably MMTk, support parallel GC, i.e. multiple GC
threads work in parallel during a GC.  Currently, when two GC threads
scan two iseq objects simultaneously when YJIT is enabled, both threads
will attempt to borrow `CodeBlock::mem_block`, which will result in
panic.

This commit makes one part of the change.

We now set the YJIT code memory to writable in bulk before the
reference-updating phase, and reset it to executable in bulk after the
reference-updating phase.  Previously, YJIT lazily sets memory pages
writable while updating object references embedded in JIT-compiled
machine code, and sets the memory back to executable by calling
`mark_all_executable`.  This approach is inherently unfriendly to
parallel GC because (1) it borrows `CodeBlock::mem_block`, and (2) it
sets the whole `CodeBlock` as executable which races with other GC
threads that are updating other iseq objects.  It also has performance
overhead due to the frequent invocation of system calls.  We now set the
permission of all the code memory in bulk before and after the reference
updating phase.  Multiple GC threads can now perform raw memory writes
in parallel.  We should also see performance improvement during moving
GC because of the reduced number of `mprotect` system calls.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Some GC modules, notably MMTk, support parallel GC, i.e. multiple GC
threads work in parallel during a GC.  Currently, when two GC threads
scan two iseq objects simultaneously when YJIT is enabled, both threads
will attempt to borrow `CodeBlock::mem_block`, which will result in
panic.

This commit makes one part of the change.

We now set the YJIT code memory to writable in bulk before the
reference-updating phase, and reset it to executable in bulk after the
reference-updating phase.  Previously, YJIT lazily sets memory pages
writable while updating object references embedded in JIT-compiled
machine code, and sets the memory back to executable by calling
`mark_all_executable`.  This approach is inherently unfriendly to
parallel GC because (1) it borrows `CodeBlock::mem_block`, and (2) it
sets the whole `CodeBlock` as executable which races with other GC
threads that are updating other iseq objects.  It also has performance
overhead due to the frequent invocation of system calls.  We now set the
permission of all the code memory in bulk before and after the reference
updating phase.  Multiple GC threads can now perform raw memory writes
in parallel.  We should also see performance improvement during moving
GC because of the reduced number of `mprotect` system calls.
</pre>
</div>
</content>
</entry>
<entry>
<title>Declaring with a prototype</title>
<updated>2025-07-02T01:15:24+00:00</updated>
<author>
<name>Nobuyoshi Nakada</name>
<email>nobu@ruby-lang.org</email>
</author>
<published>2025-07-02T01:15:24+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=f11daeb6250e161306c91786a0a02bc6bf490e35'/>
<id>f11daeb6250e161306c91786a0a02bc6bf490e35</id>
<content type='text'>
In C99, a function declaration with an empty argument list means "no
information about the arguments", not "it takes no arguments" - the
so-called old K&amp;R style.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
In C99, a function declaration with an empty argument list means "no
information about the arguments", not "it takes no arguments" - the
so-called old K&amp;R style.
</pre>
</div>
</content>
</entry>
<entry>
<title>Fix false-positive memory leak using Valgrind in YJIT (#12057)</title>
<updated>2024-11-11T20:45:11+00:00</updated>
<author>
<name>Peter Zhu</name>
<email>peter@peterzhu.ca</email>
</author>
<published>2024-11-11T20:45:11+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=1d1c80e6443e21a7e10d9d4987b0deb1ef8ec374'/>
<id>1d1c80e6443e21a7e10d9d4987b0deb1ef8ec374</id>
<content type='text'>
When we run with RUBY_FREE_AT_EXIT, there's a false-positive memory leak
reported in YJIT because the METHOD_CODEGEN_TABLE is never freed. This
commit adds rb_yjit_free_at_exit that is called at shutdown when
RUBY_FREE_AT_EXIT is set.

Reported memory leak:

    ==699816== 1,104 bytes in 1 blocks are possibly lost in loss record 1 of 1
    ==699816==    at 0x484680F: malloc (vg_replace_malloc.c:446)
    ==699816==    by 0x155B3E: UnknownInlinedFun (unix.rs:14)
    ==699816==    by 0x155B3E: UnknownInlinedFun (stats.rs:36)
    ==699816==    by 0x155B3E: UnknownInlinedFun (stats.rs:27)
    ==699816==    by 0x155B3E: alloc (alloc.rs:98)
    ==699816==    by 0x155B3E: alloc_impl (alloc.rs:181)
    ==699816==    by 0x155B3E: allocate (alloc.rs:241)
    ==699816==    by 0x155B3E: do_alloc&lt;alloc::alloc::Global&gt; (alloc.rs:15)
    ==699816==    by 0x155B3E: new_uninitialized&lt;alloc::alloc::Global&gt; (mod.rs:1750)
    ==699816==    by 0x155B3E: fallible_with_capacity&lt;alloc::alloc::Global&gt; (mod.rs:1788)
    ==699816==    by 0x155B3E: prepare_resize&lt;alloc::alloc::Global&gt; (mod.rs:2864)
    ==699816==    by 0x155B3E: resize_inner&lt;alloc::alloc::Global&gt; (mod.rs:3060)
    ==699816==    by 0x155B3E: reserve_rehash_inner&lt;alloc::alloc::Global&gt; (mod.rs:2950)
    ==699816==    by 0x155B3E: hashbrown::raw::RawTable&lt;T,A&gt;::reserve_rehash (mod.rs:1231)
    ==699816==    by 0x5BC39F: UnknownInlinedFun (mod.rs:1179)
    ==699816==    by 0x5BC39F: find_or_find_insert_slot&lt;(usize, fn(&amp;mut yjit::codegen::JITState, &amp;mut yjit::backend::ir::Assembler, *const yjit::cruby::autogened::rb_callinfo, *const yjit::cruby::autogened::rb_callable_method_entry_struct, core::option::Option&lt;yjit::codegen::BlockHandler&gt;, i32, core::option::Option&lt;yjit::cruby::VALUE&gt;) -&gt; bool), alloc::alloc::Global, hashbrown::map::equivalent_key::{closure_env#0}&lt;usize, usize, fn(&amp;mut yjit::codegen::JITState, &amp;mut yjit::backend::ir::Assembler, *const yjit::cruby::autogened::rb_callinfo, *const yjit::cruby::autogened::rb_callable_method_entry_struct, core::option::Option&lt;yjit::codegen::BlockHandler&gt;, i32, core::option::Option&lt;yjit::cruby::VALUE&gt;) -&gt; bool&gt;, hashbrown::map::make_hasher::{closure_env#0}&lt;usize, fn(&amp;mut yjit::codegen::JITState, &amp;mut yjit::backend::ir::Assembler, *const yjit::cruby::autogened::rb_callinfo, *const yjit::cruby::autogened::rb_callable_method_entry_struct, core::option::Option&lt;yjit::codegen::BlockHandler&gt;, i32, core::option::Option&lt;yjit::cruby::VALUE&gt;) -&gt; bool, std::hash::random::RandomState&gt;&gt; (mod.rs:1413)
    ==699816==    by 0x5BC39F: hashbrown::map::HashMap&lt;K,V,S,A&gt;::insert (map.rs:1754)
    ==699816==    by 0x57C5C6: insert&lt;usize, fn(&amp;mut yjit::codegen::JITState, &amp;mut yjit::backend::ir::Assembler, *const yjit::cruby::autogened::rb_callinfo, *const yjit::cruby::autogened::rb_callable_method_entry_struct, core::option::Option&lt;yjit::codegen::BlockHandler&gt;, i32, core::option::Option&lt;yjit::cruby::VALUE&gt;) -&gt; bool, std::hash::random::RandomState&gt; (map.rs:1104)
    ==699816==    by 0x57C5C6: yjit::codegen::reg_method_codegen (codegen.rs:10521)
    ==699816==    by 0x57C295: yjit::codegen::yjit_reg_method_codegen_fns (codegen.rs:10464)
    ==699816==    by 0x5C6B07: rb_yjit_init (yjit.rs:40)
    ==699816==    by 0x393723: ruby_opt_init (ruby.c:1820)
    ==699816==    by 0x393723: ruby_opt_init (ruby.c:1767)
    ==699816==    by 0x3957D4: prism_script (ruby.c:2215)
    ==699816==    by 0x3957D4: process_options (ruby.c:2538)
    ==699816==    by 0x396065: ruby_process_options (ruby.c:3166)
    ==699816==    by 0x236E56: ruby_options (eval.c:117)
    ==699816==    by 0x15BAED: rb_main (main.c:43)
    ==699816==    by 0x15BAED: main (main.c:62)

After this patch, there are no more memory leaks reported when running
RUBY_FREE_AT_EXIT with Valgrind on an empty Ruby script:

    $ RUBY_FREE_AT_EXIT=1 valgrind --leak-check=full ruby -e ""
    ...
    ==700357== HEAP SUMMARY:
    ==700357==     in use at exit: 0 bytes in 0 blocks
    ==700357==   total heap usage: 36,559 allocs, 36,559 frees, 6,064,783 bytes allocated
    ==700357==
    ==700357== All heap blocks were freed -- no leaks are possible</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
When we run with RUBY_FREE_AT_EXIT, there's a false-positive memory leak
reported in YJIT because the METHOD_CODEGEN_TABLE is never freed. This
commit adds rb_yjit_free_at_exit that is called at shutdown when
RUBY_FREE_AT_EXIT is set.

Reported memory leak:

    ==699816== 1,104 bytes in 1 blocks are possibly lost in loss record 1 of 1
    ==699816==    at 0x484680F: malloc (vg_replace_malloc.c:446)
    ==699816==    by 0x155B3E: UnknownInlinedFun (unix.rs:14)
    ==699816==    by 0x155B3E: UnknownInlinedFun (stats.rs:36)
    ==699816==    by 0x155B3E: UnknownInlinedFun (stats.rs:27)
    ==699816==    by 0x155B3E: alloc (alloc.rs:98)
    ==699816==    by 0x155B3E: alloc_impl (alloc.rs:181)
    ==699816==    by 0x155B3E: allocate (alloc.rs:241)
    ==699816==    by 0x155B3E: do_alloc&lt;alloc::alloc::Global&gt; (alloc.rs:15)
    ==699816==    by 0x155B3E: new_uninitialized&lt;alloc::alloc::Global&gt; (mod.rs:1750)
    ==699816==    by 0x155B3E: fallible_with_capacity&lt;alloc::alloc::Global&gt; (mod.rs:1788)
    ==699816==    by 0x155B3E: prepare_resize&lt;alloc::alloc::Global&gt; (mod.rs:2864)
    ==699816==    by 0x155B3E: resize_inner&lt;alloc::alloc::Global&gt; (mod.rs:3060)
    ==699816==    by 0x155B3E: reserve_rehash_inner&lt;alloc::alloc::Global&gt; (mod.rs:2950)
    ==699816==    by 0x155B3E: hashbrown::raw::RawTable&lt;T,A&gt;::reserve_rehash (mod.rs:1231)
    ==699816==    by 0x5BC39F: UnknownInlinedFun (mod.rs:1179)
    ==699816==    by 0x5BC39F: find_or_find_insert_slot&lt;(usize, fn(&amp;mut yjit::codegen::JITState, &amp;mut yjit::backend::ir::Assembler, *const yjit::cruby::autogened::rb_callinfo, *const yjit::cruby::autogened::rb_callable_method_entry_struct, core::option::Option&lt;yjit::codegen::BlockHandler&gt;, i32, core::option::Option&lt;yjit::cruby::VALUE&gt;) -&gt; bool), alloc::alloc::Global, hashbrown::map::equivalent_key::{closure_env#0}&lt;usize, usize, fn(&amp;mut yjit::codegen::JITState, &amp;mut yjit::backend::ir::Assembler, *const yjit::cruby::autogened::rb_callinfo, *const yjit::cruby::autogened::rb_callable_method_entry_struct, core::option::Option&lt;yjit::codegen::BlockHandler&gt;, i32, core::option::Option&lt;yjit::cruby::VALUE&gt;) -&gt; bool&gt;, hashbrown::map::make_hasher::{closure_env#0}&lt;usize, fn(&amp;mut yjit::codegen::JITState, &amp;mut yjit::backend::ir::Assembler, *const yjit::cruby::autogened::rb_callinfo, *const yjit::cruby::autogened::rb_callable_method_entry_struct, core::option::Option&lt;yjit::codegen::BlockHandler&gt;, i32, core::option::Option&lt;yjit::cruby::VALUE&gt;) -&gt; bool, std::hash::random::RandomState&gt;&gt; (mod.rs:1413)
    ==699816==    by 0x5BC39F: hashbrown::map::HashMap&lt;K,V,S,A&gt;::insert (map.rs:1754)
    ==699816==    by 0x57C5C6: insert&lt;usize, fn(&amp;mut yjit::codegen::JITState, &amp;mut yjit::backend::ir::Assembler, *const yjit::cruby::autogened::rb_callinfo, *const yjit::cruby::autogened::rb_callable_method_entry_struct, core::option::Option&lt;yjit::codegen::BlockHandler&gt;, i32, core::option::Option&lt;yjit::cruby::VALUE&gt;) -&gt; bool, std::hash::random::RandomState&gt; (map.rs:1104)
    ==699816==    by 0x57C5C6: yjit::codegen::reg_method_codegen (codegen.rs:10521)
    ==699816==    by 0x57C295: yjit::codegen::yjit_reg_method_codegen_fns (codegen.rs:10464)
    ==699816==    by 0x5C6B07: rb_yjit_init (yjit.rs:40)
    ==699816==    by 0x393723: ruby_opt_init (ruby.c:1820)
    ==699816==    by 0x393723: ruby_opt_init (ruby.c:1767)
    ==699816==    by 0x3957D4: prism_script (ruby.c:2215)
    ==699816==    by 0x3957D4: process_options (ruby.c:2538)
    ==699816==    by 0x396065: ruby_process_options (ruby.c:3166)
    ==699816==    by 0x236E56: ruby_options (eval.c:117)
    ==699816==    by 0x15BAED: rb_main (main.c:43)
    ==699816==    by 0x15BAED: main (main.c:62)

After this patch, there are no more memory leaks reported when running
RUBY_FREE_AT_EXIT with Valgrind on an empty Ruby script:

    $ RUBY_FREE_AT_EXIT=1 valgrind --leak-check=full ruby -e ""
    ...
    ==700357== HEAP SUMMARY:
    ==700357==     in use at exit: 0 bytes in 0 blocks
    ==700357==   total heap usage: 36,559 allocs, 36,559 frees, 6,064,783 bytes allocated
    ==700357==
    ==700357== All heap blocks were freed -- no leaks are possible</pre>
</div>
</content>
</entry>
<entry>
<title>YJIT: Optimize local variables when EP == BP (take 2) (#10607)</title>
<updated>2024-04-25T14:04:53+00:00</updated>
<author>
<name>Takashi Kokubun</name>
<email>takashikkbn@gmail.com</email>
</author>
<published>2024-04-25T14:04:53+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=7ab1a608e7413cdb0f93243eb3e6e20a32cec44e'/>
<id>7ab1a608e7413cdb0f93243eb3e6e20a32cec44e</id>
<content type='text'>
* Revert "Revert "YJIT: Optimize local variables when EP == BP" (#10584)"

This reverts commit c8783441952217c18e523749c821f82cd7e5d222.

* YJIT: Take care of GC references in ISEQ invariants

Co-authored-by: Alan Wu &lt;alansi.xingwu@shopify.com&gt;

---------

Co-authored-by: Alan Wu &lt;alansi.xingwu@shopify.com&gt;</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
* Revert "Revert "YJIT: Optimize local variables when EP == BP" (#10584)"

This reverts commit c8783441952217c18e523749c821f82cd7e5d222.

* YJIT: Take care of GC references in ISEQ invariants

Co-authored-by: Alan Wu &lt;alansi.xingwu@shopify.com&gt;

---------

Co-authored-by: Alan Wu &lt;alansi.xingwu@shopify.com&gt;</pre>
</div>
</content>
</entry>
<entry>
<title>Revert "YJIT: Optimize local variables when EP == BP" (#10584)</title>
<updated>2024-04-19T16:47:25+00:00</updated>
<author>
<name>Alan Wu</name>
<email>XrXr@users.noreply.github.com</email>
</author>
<published>2024-04-19T16:47:25+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=c8783441952217c18e523749c821f82cd7e5d222'/>
<id>c8783441952217c18e523749c821f82cd7e5d222</id>
<content type='text'>
This reverts commit 4cc58ea0b865f2fd20f1e881ddbd4c4fab0b072c.

Since the change landed call-threshold=1 CI runs have been timing out.
There has also been `verify-ctx` violations. Revert for now while we debug.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This reverts commit 4cc58ea0b865f2fd20f1e881ddbd4c4fab0b072c.

Since the change landed call-threshold=1 CI runs have been timing out.
There has also been `verify-ctx` violations. Revert for now while we debug.</pre>
</div>
</content>
</entry>
<entry>
<title>YJIT: Optimize local variables when EP == BP (#10487)</title>
<updated>2024-04-17T19:00:03+00:00</updated>
<author>
<name>Takashi Kokubun</name>
<email>takashikkbn@gmail.com</email>
</author>
<published>2024-04-17T19:00:03+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=4cc58ea0b865f2fd20f1e881ddbd4c4fab0b072c'/>
<id>4cc58ea0b865f2fd20f1e881ddbd4c4fab0b072c</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>YJIT: add iseq_alloc_count to stats (#10398)</title>
<updated>2024-03-28T19:21:09+00:00</updated>
<author>
<name>Maxime Chevalier-Boisvert</name>
<email>maxime.chevalierboisvert@shopify.com</email>
</author>
<published>2024-03-28T19:21:09+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=bb3cbdfe2fcbfc2b6c7ee8699d35fde838615c26'/>
<id>bb3cbdfe2fcbfc2b6c7ee8699d35fde838615c26</id>
<content type='text'>
* YJIT: add iseq_alloc_count to stats

* Remove an empty line

---------

Co-authored-by: Takashi Kokubun &lt;takashikkbn@gmail.com&gt;</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
* YJIT: add iseq_alloc_count to stats

* Remove an empty line

---------

Co-authored-by: Takashi Kokubun &lt;takashikkbn@gmail.com&gt;</pre>
</div>
</content>
</entry>
<entry>
<title>YJIT: Propagate Array, Hash, and String classes (#10323)</title>
<updated>2024-03-25T16:06:47+00:00</updated>
<author>
<name>Takashi Kokubun</name>
<email>takashikkbn@gmail.com</email>
</author>
<published>2024-03-25T16:06:47+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=46bf6ae886dc14d5e3a76d53eb4f97375f7c03c5'/>
<id>46bf6ae886dc14d5e3a76d53eb4f97375f7c03c5</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>YJIT: Lazily push a frame for specialized C funcs (#10080)</title>
<updated>2024-02-23T19:08:09+00:00</updated>
<author>
<name>Takashi Kokubun</name>
<email>takashikkbn@gmail.com</email>
</author>
<published>2024-02-23T19:08:09+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=8a6740c70edf39cdf6230659d191240c43dc6d22'/>
<id>8a6740c70edf39cdf6230659d191240c43dc6d22</id>
<content type='text'>
* YJIT: Lazily push a frame for specialized C funcs

Co-authored-by: Maxime Chevalier-Boisvert &lt;maxime.chevalierboisvert@shopify.com&gt;

* Fix a comment on pc_to_cfunc

* Rename rb_yjit_check_pc to rb_yjit_lazy_push_frame

* Rename it to jit_prepare_lazy_frame_call

* Fix a typo

* Optimize String#getbyte as well

* Optimize String#byteslice as well

---------

Co-authored-by: Maxime Chevalier-Boisvert &lt;maxime.chevalierboisvert@shopify.com&gt;</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
* YJIT: Lazily push a frame for specialized C funcs

Co-authored-by: Maxime Chevalier-Boisvert &lt;maxime.chevalierboisvert@shopify.com&gt;

* Fix a comment on pc_to_cfunc

* Rename rb_yjit_check_pc to rb_yjit_lazy_push_frame

* Rename it to jit_prepare_lazy_frame_call

* Fix a typo

* Optimize String#getbyte as well

* Optimize String#byteslice as well

---------

Co-authored-by: Maxime Chevalier-Boisvert &lt;maxime.chevalierboisvert@shopify.com&gt;</pre>
</div>
</content>
</entry>
</feed>
