<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ruby.git/yjit/src/asm, branch v3_2_11</title>
<subtitle>The Ruby Programming Language</subtitle>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/'/>
<entry>
<title>[For ruby_3_2] Fix unused_mut Rust warnings (#8435)</title>
<updated>2023-09-16T04:06:39+00:00</updated>
<author>
<name>Alan Wu</name>
<email>XrXr@users.noreply.github.com</email>
</author>
<published>2023-09-16T04:06:39+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=e159971e03102090e29f3555975498f75cf02f2c'/>
<id>e159971e03102090e29f3555975498f75cf02f2c</id>
<content type='text'>
Fix unused_mut Rust warnings

Rust version 1.71.0 and up issue these warnings. On GitHub CI, the
warnings were previously seen in -DYJIT_FORCE_ENABLE runs.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Fix unused_mut Rust warnings

Rust version 1.71.0 and up issue these warnings. On GitHub CI, the
warnings were previously seen in -DYJIT_FORCE_ENABLE runs.</pre>
</div>
</content>
</entry>
<entry>
<title>merge revision(s) b78f871d838c168789648738e5c67b071beb8a19,ecd0cdaf820af789f355f1a18c31d6adfe8aad94: [Backport #19400]</title>
<updated>2023-03-04T06:39:47+00:00</updated>
<author>
<name>NARUSE, Yui</name>
<email>naruse@airemix.jp</email>
</author>
<published>2023-03-04T06:39:47+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=f93c7b9f58966fd04496bfeb2538fb1ff41f788e'/>
<id>f93c7b9f58966fd04496bfeb2538fb1ff41f788e</id>
<content type='text'>
	YJIT: Use the system page size when the code page size is too small
	 (#7267)

	Previously on ARM64 Linux systems that use 64 KiB pages
	(`CONFIG_ARM64_64K_PAGES=y`), YJIT was panicking on boot due to a failed
	assertion.

	The assertion was making sure that code GC can free the last code page
	that YJIT manages without freeing unrelated memory. YJIT prefers picking
	16 KiB as the granularity at which to free code memory, but when the
	system can only free at 64 KiB granularity, that is not possible.

	The fix is to use the system page size as the code page size when the
	system page size is 64 KiB. Continue to use 16 KiB as the code page size
	on common systems that use 16/4 KiB pages.

	Add asserts to code_gc() and free_page() about code GC's assumptions.

	Fixes [Bug #19400]
	---
	 yjit/src/asm/mod.rs    | 78 ++++++++++++++++++++++++++++++++------------------
	 yjit/src/codegen.rs    |  2 --
	 yjit/src/virtualmem.rs | 13 +++++++++
	 3 files changed, 63 insertions(+), 30 deletions(-)

	YJIT: Fix assertion for partially mapped last pages (#7337)

	Follows up [Bug #19400]
	---
	 test/ruby/test_yjit.rb | 19 +++++++++++++++++++
	 yjit/src/asm/mod.rs    |  2 +-
	 yjit/src/virtualmem.rs | 18 +++++++++++++-----
	 3 files changed, 33 insertions(+), 6 deletions(-)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
	YJIT: Use the system page size when the code page size is too small
	 (#7267)

	Previously on ARM64 Linux systems that use 64 KiB pages
	(`CONFIG_ARM64_64K_PAGES=y`), YJIT was panicking on boot due to a failed
	assertion.

	The assertion was making sure that code GC can free the last code page
	that YJIT manages without freeing unrelated memory. YJIT prefers picking
	16 KiB as the granularity at which to free code memory, but when the
	system can only free at 64 KiB granularity, that is not possible.

	The fix is to use the system page size as the code page size when the
	system page size is 64 KiB. Continue to use 16 KiB as the code page size
	on common systems that use 16/4 KiB pages.

	Add asserts to code_gc() and free_page() about code GC's assumptions.

	Fixes [Bug #19400]
	---
	 yjit/src/asm/mod.rs    | 78 ++++++++++++++++++++++++++++++++------------------
	 yjit/src/codegen.rs    |  2 --
	 yjit/src/virtualmem.rs | 13 +++++++++
	 3 files changed, 63 insertions(+), 30 deletions(-)

	YJIT: Fix assertion for partially mapped last pages (#7337)

	Follows up [Bug #19400]
	---
	 test/ruby/test_yjit.rb | 19 +++++++++++++++++++
	 yjit/src/asm/mod.rs    |  2 +-
	 yjit/src/virtualmem.rs | 18 +++++++++++++-----
	 3 files changed, 33 insertions(+), 6 deletions(-)
</pre>
</div>
</content>
</entry>
<entry>
<title>merge revision(s) 188688a53e7708d25ab80e14d05e70ffcf792e13: [Backport #19385]</title>
<updated>2023-02-03T05:13:09+00:00</updated>
<author>
<name>NARUSE, Yui</name>
<email>naruse@airemix.jp</email>
</author>
<published>2023-02-03T05:13:02+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=535d863f34e6c36a2378683e7c2d3b7369e3d076'/>
<id>535d863f34e6c36a2378683e7c2d3b7369e3d076</id>
<content type='text'>
	[PATCH 1/4] YJIT: Move CodegenGlobals::freed_pages into an Rc

	This allows for supplying a freed_pages vec in Rust tests. We need it so we
	can test scenarios that occur after code GC.
	---
	 yjit/src/asm/mod.rs | 48 +++++++++++++++++++++++++++++++++------------
	 yjit/src/codegen.rs | 16 ++++-----------
	 2 files changed, 39 insertions(+), 25 deletions(-)

	Subject: [PATCH 2/4] YJIT: other_cb is None in tests

	Since the other cb is in CodegenGlobals, and we want Rust tests to be
	self-contained.
	---
	 yjit/src/asm/mod.rs | 1 +
	 1 file changed, 1 insertion(+)

	Subject: [PATCH 3/4] YJIT: ARM64: Move functions out of arm64_emit()

	---
	 yjit/src/backend/arm64/mod.rs | 180 +++++++++++++++++-----------------
	 1 file changed, 90 insertions(+), 90 deletions(-)

	Subject: [PATCH 4/4] YJIT: ARM64: Fix long jumps to labels

	Previously, with Code GC, YJIT panicked while trying to emit a B.cond
	instruction with an offset that is not encodable in 19 bits. This only
	happens when the code in an assembler instance straddles two pages.

	To fix this, when we detect that a jump to a label can land on a
	different page, we switch to a fresh new page and regenerate all the
	code in the assembler there. We still assume that no one assembler has
	so much code that it wouldn't fit inside a fresh new page.

	[Bug #19385]
	---
	 yjit/src/backend/arm64/mod.rs | 65 ++++++++++++++++++++++++++++++++---
	 1 file changed, 60 insertions(+), 5 deletions(-)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
	[PATCH 1/4] YJIT: Move CodegenGlobals::freed_pages into an Rc

	This allows for supplying a freed_pages vec in Rust tests. We need it so we
	can test scenarios that occur after code GC.
	---
	 yjit/src/asm/mod.rs | 48 +++++++++++++++++++++++++++++++++------------
	 yjit/src/codegen.rs | 16 ++++-----------
	 2 files changed, 39 insertions(+), 25 deletions(-)

	Subject: [PATCH 2/4] YJIT: other_cb is None in tests

	Since the other cb is in CodegenGlobals, and we want Rust tests to be
	self-contained.
	---
	 yjit/src/asm/mod.rs | 1 +
	 1 file changed, 1 insertion(+)

	Subject: [PATCH 3/4] YJIT: ARM64: Move functions out of arm64_emit()

	---
	 yjit/src/backend/arm64/mod.rs | 180 +++++++++++++++++-----------------
	 1 file changed, 90 insertions(+), 90 deletions(-)

	Subject: [PATCH 4/4] YJIT: ARM64: Fix long jumps to labels

	Previously, with Code GC, YJIT panicked while trying to emit a B.cond
	instruction with an offset that is not encodable in 19 bits. This only
	happens when the code in an assembler instance straddles two pages.

	To fix this, when we detect that a jump to a label can land on a
	different page, we switch to a fresh new page and regenerate all the
	code in the assembler there. We still assume that no one assembler has
	so much code that it wouldn't fit inside a fresh new page.

	[Bug #19385]
	---
	 yjit/src/backend/arm64/mod.rs | 65 ++++++++++++++++++++++++++++++++---
	 1 file changed, 60 insertions(+), 5 deletions(-)
</pre>
</div>
</content>
</entry>
<entry>
<title>YJIT: Remove --yjit-code-page-size (#6865)</title>
<updated>2022-12-05T22:43:17+00:00</updated>
<author>
<name>Alan Wu</name>
<email>XrXr@users.noreply.github.com</email>
</author>
<published>2022-12-05T22:43:17+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=235fc50447c13b054d8849ef2fcdac55ef1f5f9c'/>
<id>235fc50447c13b054d8849ef2fcdac55ef1f5f9c</id>
<content type='text'>
Certain code page sizes don't work and can cause crashes, so having this
value available as a command-line option is a bit dangerous. Remove it
and turn it into a constant instead.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Certain code page sizes don't work and can cause crashes, so having this
value available as a command-line option is a bit dangerous. Remove it
and turn it into a constant instead.</pre>
</div>
</content>
</entry>
<entry>
<title>YJIT: Respect destination num_bits on STUR (#6848)</title>
<updated>2022-12-02T00:13:38+00:00</updated>
<author>
<name>Takashi Kokubun</name>
<email>takashikkbn@gmail.com</email>
</author>
<published>2022-12-02T00:13:38+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=dcbea7671be74a328f115c6410980f54c872c478'/>
<id>dcbea7671be74a328f115c6410980f54c872c478</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 32 and 16 bit register store (#6840)</title>
<updated>2022-12-01T15:53:50+00:00</updated>
<author>
<name>Jemma Issroff</name>
<email>jemmaissroff@gmail.com</email>
</author>
<published>2022-12-01T15:53:50+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=06a0c580161db7084e8276fcd9fbb5d25bde4a03'/>
<id>06a0c580161db7084e8276fcd9fbb5d25bde4a03</id>
<content type='text'>
* Fix 32 and 16 bit register store in YJIT

Co-Authored-By: Takashi Kokubun &lt;takashikkbn@gmail.com&gt;

* Remove an unnecessary diff

* Reuse an rm_num_bits result

* Use u16::MAX instead

* Update the link

Co-authored-by: Alan Wu &lt;XrXr@users.noreply.github.com&gt;

* Just use sturh for 16 bits

Co-authored-by: Takashi Kokubun &lt;takashikkbn@gmail.com&gt;
Co-authored-by: Alan Wu &lt;XrXr@users.noreply.github.com&gt;</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
* Fix 32 and 16 bit register store in YJIT

Co-Authored-By: Takashi Kokubun &lt;takashikkbn@gmail.com&gt;

* Remove an unnecessary diff

* Reuse an rm_num_bits result

* Use u16::MAX instead

* Update the link

Co-authored-by: Alan Wu &lt;XrXr@users.noreply.github.com&gt;

* Just use sturh for 16 bits

Co-authored-by: Takashi Kokubun &lt;takashikkbn@gmail.com&gt;
Co-authored-by: Alan Wu &lt;XrXr@users.noreply.github.com&gt;</pre>
</div>
</content>
</entry>
<entry>
<title>YJIT: Fix IseqPayload::pages memory bloat</title>
<updated>2022-11-30T17:23:50+00:00</updated>
<author>
<name>Alan Wu</name>
<email>XrXr@users.noreply.github.com</email>
</author>
<published>2022-11-29T20:37:29+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=03f1e6a2aa8aa1d5aef79a33a243372a457f0fa2'/>
<id>03f1e6a2aa8aa1d5aef79a33a243372a457f0fa2</id>
<content type='text'>
HashSet::clear() doesn't deallocate the backing buffer and shrink the
capacity. Replace with a 0-capcity set instead so we reclaim some memory
each code GC.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
HashSet::clear() doesn't deallocate the backing buffer and shrink the
capacity. Replace with a 0-capcity set instead so we reclaim some memory
each code GC.
</pre>
</div>
</content>
</entry>
<entry>
<title>YJIT: Use NonNull pointer for CodePtr (#6792)</title>
<updated>2022-11-23T17:02:05+00:00</updated>
<author>
<name>Takashi Kokubun</name>
<email>takashikkbn@gmail.com</email>
</author>
<published>2022-11-23T17:02:05+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=d88adaad7ea4761bd36c957260667840472fd2dc'/>
<id>d88adaad7ea4761bd36c957260667840472fd2dc</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>Fix YJIT backend to account for unsigned int immediates (#6789)</title>
<updated>2022-11-23T15:48:17+00:00</updated>
<author>
<name>Jemma Issroff</name>
<email>jemmaissroff@gmail.com</email>
</author>
<published>2022-11-23T15:48:17+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=e82b15b6603ddc6754f4cfa7a189c0acb0ccce71'/>
<id>e82b15b6603ddc6754f4cfa7a189c0acb0ccce71</id>
<content type='text'>
YJIT: x86_64: Fix cmp with number where sign bit is set

Before this commit, we were unconditionally treating unsigned ints as
signed ints when counting the number of bits required for representing
the immediate in machine code. When the size of the immediate matches
the size of the other operand, no sign extension happens, so this was
incorrect. `asm.cmp(opnd64, 0x8000_0000)` panicked even though it's
encodable as `CMP r/m32, imm32`. Large shape ids were impacted by this
issue.

Co-Authored-By: Aaron Patterson &lt;tenderlove@ruby-lang.org&gt;
Co-Authored-By: Alan Wu &lt;alanwu@ruby-lang.org&gt;

Co-authored-by: Aaron Patterson &lt;tenderlove@ruby-lang.org&gt;
Co-authored-by: Alan Wu &lt;alanwu@ruby-lang.org&gt;</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
YJIT: x86_64: Fix cmp with number where sign bit is set

Before this commit, we were unconditionally treating unsigned ints as
signed ints when counting the number of bits required for representing
the immediate in machine code. When the size of the immediate matches
the size of the other operand, no sign extension happens, so this was
incorrect. `asm.cmp(opnd64, 0x8000_0000)` panicked even though it's
encodable as `CMP r/m32, imm32`. Large shape ids were impacted by this
issue.

Co-Authored-By: Aaron Patterson &lt;tenderlove@ruby-lang.org&gt;
Co-Authored-By: Alan Wu &lt;alanwu@ruby-lang.org&gt;

Co-authored-by: Aaron Patterson &lt;tenderlove@ruby-lang.org&gt;
Co-authored-by: Alan Wu &lt;alanwu@ruby-lang.org&gt;</pre>
</div>
</content>
</entry>
<entry>
<title>32 bit comparison on shape id</title>
<updated>2022-11-18T20:04:10+00:00</updated>
<author>
<name>Aaron Patterson</name>
<email>tenderlove@ruby-lang.org</email>
</author>
<published>2022-11-15T19:46:18+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=9e067df76bda7384e8f3ddda2b348f3a742eb784'/>
<id>9e067df76bda7384e8f3ddda2b348f3a742eb784</id>
<content type='text'>
This commit changes the shape id comparisons to use a 32 bit comparison
rather than 64 bit.  That means we don't need to load the shape id to a
register on x86 machines.

Given the following program:

```ruby
class Foo
  def initialize
    @foo = 1
    @bar = 1
  end

  def read
    [@foo, @bar]
  end
end

foo = Foo.new
foo.read
foo.read
foo.read
foo.read
foo.read

puts RubyVM::YJIT.disasm(Foo.instance_method(:read))
```

The machine code we generated _before_ this change is like this:

```
== BLOCK 1/4, ISEQ RANGE [0,3), 65 bytes ======================
  # getinstancevariable
  0x559a18623023: mov rax, qword ptr [r13 + 0x18]
  # guard object is heap
  0x559a18623027: test al, 7
  0x559a1862302a: jne 0x559a1862502d
  0x559a18623030: cmp rax, 4
  0x559a18623034: jbe 0x559a1862502d
  # guard shape, embedded, and T_OBJECT
  0x559a1862303a: mov rcx, qword ptr [rax]
  0x559a1862303d: movabs r11, 0xffff00000000201f
  0x559a18623047: and rcx, r11
  0x559a1862304a: movabs r11, 0xb000000002001
  0x559a18623054: cmp rcx, r11
  0x559a18623057: jne 0x559a18625046
  0x559a1862305d: mov rax, qword ptr [rax + 0x18]
  0x559a18623061: mov qword ptr [rbx], rax

== BLOCK 2/4, ISEQ RANGE [3,6), 0 bytes =======================
== BLOCK 3/4, ISEQ RANGE [3,6), 47 bytes ======================
  # gen_direct_jmp: fallthrough
  # getinstancevariable
  # regenerate_branch
  # getinstancevariable
  # regenerate_branch
  0x559a18623064: mov rax, qword ptr [r13 + 0x18]
  # guard shape, embedded, and T_OBJECT
  0x559a18623068: mov rcx, qword ptr [rax]
  0x559a1862306b: movabs r11, 0xffff00000000201f
  0x559a18623075: and rcx, r11
  0x559a18623078: movabs r11, 0xb000000002001
  0x559a18623082: cmp rcx, r11
  0x559a18623085: jne 0x559a18625099
  0x559a1862308b: mov rax, qword ptr [rax + 0x20]
  0x559a1862308f: mov qword ptr [rbx + 8], rax
```

After this change, it's like this:

```
== BLOCK 1/4, ISEQ RANGE [0,3), 41 bytes ======================
  # getinstancevariable
  0x5560c986d023: mov rax, qword ptr [r13 + 0x18]
  # guard object is heap
  0x5560c986d027: test al, 7
  0x5560c986d02a: jne 0x5560c986f02d
  0x5560c986d030: cmp rax, 4
  0x5560c986d034: jbe 0x5560c986f02d
  # guard shape
  0x5560c986d03a: cmp word ptr [rax + 6], 0x19
  0x5560c986d03f: jne 0x5560c986f046
  0x5560c986d045: mov rax, qword ptr [rax + 0x10]
  0x5560c986d049: mov qword ptr [rbx], rax

== BLOCK 2/4, ISEQ RANGE [3,6), 0 bytes =======================
== BLOCK 3/4, ISEQ RANGE [3,6), 23 bytes ======================
  # gen_direct_jmp: fallthrough
  # getinstancevariable
  # regenerate_branch
  # getinstancevariable
  # regenerate_branch
  0x5560c986d04c: mov rax, qword ptr [r13 + 0x18]
  # guard shape
  0x5560c986d050: cmp word ptr [rax + 6], 0x19
  0x5560c986d055: jne 0x5560c986f099
  0x5560c986d05b: mov rax, qword ptr [rax + 0x18]
  0x5560c986d05f: mov qword ptr [rbx + 8], rax
```

The first ivar read is a bit more complex, but the second ivar read is
much simpler.  I think eventually we could teach the context about the
shape, then emit only one shape guard.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This commit changes the shape id comparisons to use a 32 bit comparison
rather than 64 bit.  That means we don't need to load the shape id to a
register on x86 machines.

Given the following program:

```ruby
class Foo
  def initialize
    @foo = 1
    @bar = 1
  end

  def read
    [@foo, @bar]
  end
end

foo = Foo.new
foo.read
foo.read
foo.read
foo.read
foo.read

puts RubyVM::YJIT.disasm(Foo.instance_method(:read))
```

The machine code we generated _before_ this change is like this:

```
== BLOCK 1/4, ISEQ RANGE [0,3), 65 bytes ======================
  # getinstancevariable
  0x559a18623023: mov rax, qword ptr [r13 + 0x18]
  # guard object is heap
  0x559a18623027: test al, 7
  0x559a1862302a: jne 0x559a1862502d
  0x559a18623030: cmp rax, 4
  0x559a18623034: jbe 0x559a1862502d
  # guard shape, embedded, and T_OBJECT
  0x559a1862303a: mov rcx, qword ptr [rax]
  0x559a1862303d: movabs r11, 0xffff00000000201f
  0x559a18623047: and rcx, r11
  0x559a1862304a: movabs r11, 0xb000000002001
  0x559a18623054: cmp rcx, r11
  0x559a18623057: jne 0x559a18625046
  0x559a1862305d: mov rax, qword ptr [rax + 0x18]
  0x559a18623061: mov qword ptr [rbx], rax

== BLOCK 2/4, ISEQ RANGE [3,6), 0 bytes =======================
== BLOCK 3/4, ISEQ RANGE [3,6), 47 bytes ======================
  # gen_direct_jmp: fallthrough
  # getinstancevariable
  # regenerate_branch
  # getinstancevariable
  # regenerate_branch
  0x559a18623064: mov rax, qword ptr [r13 + 0x18]
  # guard shape, embedded, and T_OBJECT
  0x559a18623068: mov rcx, qword ptr [rax]
  0x559a1862306b: movabs r11, 0xffff00000000201f
  0x559a18623075: and rcx, r11
  0x559a18623078: movabs r11, 0xb000000002001
  0x559a18623082: cmp rcx, r11
  0x559a18623085: jne 0x559a18625099
  0x559a1862308b: mov rax, qword ptr [rax + 0x20]
  0x559a1862308f: mov qword ptr [rbx + 8], rax
```

After this change, it's like this:

```
== BLOCK 1/4, ISEQ RANGE [0,3), 41 bytes ======================
  # getinstancevariable
  0x5560c986d023: mov rax, qword ptr [r13 + 0x18]
  # guard object is heap
  0x5560c986d027: test al, 7
  0x5560c986d02a: jne 0x5560c986f02d
  0x5560c986d030: cmp rax, 4
  0x5560c986d034: jbe 0x5560c986f02d
  # guard shape
  0x5560c986d03a: cmp word ptr [rax + 6], 0x19
  0x5560c986d03f: jne 0x5560c986f046
  0x5560c986d045: mov rax, qword ptr [rax + 0x10]
  0x5560c986d049: mov qword ptr [rbx], rax

== BLOCK 2/4, ISEQ RANGE [3,6), 0 bytes =======================
== BLOCK 3/4, ISEQ RANGE [3,6), 23 bytes ======================
  # gen_direct_jmp: fallthrough
  # getinstancevariable
  # regenerate_branch
  # getinstancevariable
  # regenerate_branch
  0x5560c986d04c: mov rax, qword ptr [r13 + 0x18]
  # guard shape
  0x5560c986d050: cmp word ptr [rax + 6], 0x19
  0x5560c986d055: jne 0x5560c986f099
  0x5560c986d05b: mov rax, qword ptr [rax + 0x18]
  0x5560c986d05f: mov qword ptr [rbx + 8], rax
```

The first ivar read is a bit more complex, but the second ivar read is
much simpler.  I think eventually we could teach the context about the
shape, then emit only one shape guard.
</pre>
</div>
</content>
</entry>
</feed>
