<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ruby.git/yjit/src/core.rs, branch v4.0.2</title>
<subtitle>The Ruby Programming Language</subtitle>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/'/>
<entry>
<title>YJIT: Print `Rc` strong and weak count on assert failure</title>
<updated>2025-12-16T19:56:40+00:00</updated>
<author>
<name>Alan Wu</name>
<email>XrXr@users.noreply.github.com</email>
</author>
<published>2025-12-16T18:33:47+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=eaa952b536c48658a5a2e3f128e3afdef03a01b6'/>
<id>eaa952b536c48658a5a2e3f128e3afdef03a01b6</id>
<content type='text'>
For &lt;https://bugs.ruby-lang.org/issues/21716&gt;, the panic is looking like
some sort of third party memory corruption, with YJIT taking the fall.
At the point of this assert, the assembler has dropped, so there's
nothing in YJIT's code other than JITState that could be holding on to
these transient `PendingBranchRef`.

The strong count being more than a handful or the weak count is non-zero
shows that someone in the process (likely some native extension)
corrupted the Rc's counts.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
For &lt;https://bugs.ruby-lang.org/issues/21716&gt;, the panic is looking like
some sort of third party memory corruption, with YJIT taking the fall.
At the point of this assert, the assembler has dropped, so there's
nothing in YJIT's code other than JITState that could be holding on to
these transient `PendingBranchRef`.

The strong count being more than a handful or the weak count is non-zero
shows that someone in the process (likely some native extension)
corrupted the Rc's counts.
</pre>
</div>
</content>
</entry>
<entry>
<title>[DOC] Fix minor typos in YJIT comments (#14829)</title>
<updated>2025-10-14T11:05:18+00:00</updated>
<author>
<name>Vincent Lin</name>
<email>bugtender@users.noreply.github.com</email>
</author>
<published>2025-10-14T11:05:18+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=34ee5cbf13d42d2fc48f48cbf787571d0c6e5729'/>
<id>34ee5cbf13d42d2fc48f48cbf787571d0c6e5729</id>
<content type='text'>
[DOC] Fix typos in YJIT core</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
[DOC] Fix typos in YJIT core</pre>
</div>
</content>
</entry>
<entry>
<title>YJIT: Prevent making a branch from a dead block to a live block</title>
<updated>2025-10-02T16:09:40+00:00</updated>
<author>
<name>Alan Wu</name>
<email>XrXr@users.noreply.github.com</email>
</author>
<published>2025-10-02T03:53:48+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=20fc91df395b834ecaee0bdb29df8da224fdf89a'/>
<id>20fc91df395b834ecaee0bdb29df8da224fdf89a</id>
<content type='text'>
I'm seeing some memory corruption in the wild on blocks in
`IseqPayload::dead_blocks`. While I unfortunately can't recreate the
issue, (For all I know, it could be some external code corrupting YJIT's
memory.) establishing a link between dead blocks and live blocks seems
fishy enough that we ought to prevent it. When it did happen, it might've
had bad interacts with Code GC and the optimization to immediately
free empty blocks.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
I'm seeing some memory corruption in the wild on blocks in
`IseqPayload::dead_blocks`. While I unfortunately can't recreate the
issue, (For all I know, it could be some external code corrupting YJIT's
memory.) establishing a link between dead blocks and live blocks seems
fishy enough that we ought to prevent it. When it did happen, it might've
had bad interacts with Code GC and the optimization to immediately
free empty blocks.
</pre>
</div>
</content>
</entry>
<entry>
<title>YJIT: Tiny refactors (#14505)</title>
<updated>2025-09-10T20:37:17+00:00</updated>
<author>
<name>Stan Lo</name>
<email>stan.lo@shopify.com</email>
</author>
<published>2025-09-10T20:37:17+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=23c60e185ea7e74f0eebc27119184fb1ed844856'/>
<id>23c60e185ea7e74f0eebc27119184fb1ed844856</id>
<content type='text'>
Addressed some suggestions from clippy that made sense to me.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Addressed some suggestions from clippy that made sense to me.</pre>
</div>
</content>
</entry>
<entry>
<title>ZJIT: Clear jit entry from iseqs after TracePoint activation (#14407)</title>
<updated>2025-09-02T19:20:08+00:00</updated>
<author>
<name>Stan Lo</name>
<email>stan.lo@shopify.com</email>
</author>
<published>2025-09-02T19:20:08+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=77a421fb057c16cd82adbe6e07efe0db01bf93a5'/>
<id>77a421fb057c16cd82adbe6e07efe0db01bf93a5</id>
<content type='text'>
ZJIT: Remove JITed code after TracePoint is enabled</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
ZJIT: Remove JITed code after TracePoint is enabled</pre>
</div>
</content>
</entry>
<entry>
<title>YJIT: Use raw memory write to update pointers in code</title>
<updated>2025-07-24T15:37:44+00:00</updated>
<author>
<name>Kunshan Wang</name>
<email>wks1986@gmail.com</email>
</author>
<published>2025-07-19T08:22:46+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=5ef20b3a274e855b802edd03cd432464d2a49b35'/>
<id>5ef20b3a274e855b802edd03cd432464d2a49b35</id>
<content type='text'>
Because we have set all code memory to writable before the reference
updating phase, we can use raw memory writes directly.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Because we have set all code memory to writable before the reference
updating phase, we can use raw memory writes directly.
</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>ZJIT: Mark profiled objects when marking ISEQ (#13784)</title>
<updated>2025-07-09T23:03:23+00:00</updated>
<author>
<name>Takashi Kokubun</name>
<email>takashi.kokubun@shopify.com</email>
</author>
<published>2025-07-09T23:03:23+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=f5085c70f25fb1b435ac7d6604fc95492fe9537d'/>
<id>f5085c70f25fb1b435ac7d6604fc95492fe9537d</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>YJIT: Fix potential infinite loop when OOM (GH-13186)</title>
<updated>2025-04-28T12:50:29+00:00</updated>
<author>
<name>Rian McGuire</name>
<email>rian@rian.id.au</email>
</author>
<published>2025-04-28T12:50:29+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=80a1a1bb8ae8435b916ae4f66a483e91ad31356a'/>
<id>80a1a1bb8ae8435b916ae4f66a483e91ad31356a</id>
<content type='text'>
Avoid generating an infinite loop in the case where:
1. Block `first` is adjacent to block `second`, and the branch from `first` to
   `second` is a fallthrough, and
2. Block `second` immediately exits to the interpreter, and
3. Block `second` is invalidated and YJIT is OOM

While pondering how to fix this, I think I've stumbled on another related edge case:
1. Block `incoming_one` and `incoming_two` both branch to block `second`. Block
   `incoming_one` has a fallthrough
2. Block `second` immediately exits to the interpreter (so it starts with its exit)
3. When Block `second` is invalidated, the incoming fallthrough branch from
   `incoming_one` might be rewritten first, which overwrites the start of block
   `second` with a jump to a new branch stub.
4. YJIT runs of out memory
5. The incoming branch from `incoming_two` is then rewritten, but because we're
   OOM we can't generate a new stub, so we use `second`'s exit as the branch
   target. However `second`'s exit was already overwritten with a jump to the
   branch stub for `incoming_one`, so `incoming_two` will end up jumping to
   `incoming_one`'s branch stub.

Fixes [Bug #21257]</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Avoid generating an infinite loop in the case where:
1. Block `first` is adjacent to block `second`, and the branch from `first` to
   `second` is a fallthrough, and
2. Block `second` immediately exits to the interpreter, and
3. Block `second` is invalidated and YJIT is OOM

While pondering how to fix this, I think I've stumbled on another related edge case:
1. Block `incoming_one` and `incoming_two` both branch to block `second`. Block
   `incoming_one` has a fallthrough
2. Block `second` immediately exits to the interpreter (so it starts with its exit)
3. When Block `second` is invalidated, the incoming fallthrough branch from
   `incoming_one` might be rewritten first, which overwrites the start of block
   `second` with a jump to a new branch stub.
4. YJIT runs of out memory
5. The incoming branch from `incoming_two` is then rewritten, but because we're
   OOM we can't generate a new stub, so we use `second`'s exit as the branch
   target. However `second`'s exit was already overwritten with a jump to the
   branch stub for `incoming_one`, so `incoming_two` will end up jumping to
   `incoming_one`'s branch stub.

Fixes [Bug #21257]</pre>
</div>
</content>
</entry>
<entry>
<title>YJIT: Rename get_temp_regs2() back to get_temp_regs() (#12866)</title>
<updated>2025-03-06T15:52:49+00:00</updated>
<author>
<name>Takashi Kokubun</name>
<email>takashikkbn@gmail.com</email>
</author>
<published>2025-03-06T15:52:49+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=bb91c303bad5fcdd59b73ca1a1923f71c7efdbfd'/>
<id>bb91c303bad5fcdd59b73ca1a1923f71c7efdbfd</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
</feed>
