Skip to content

Instantly share code, notes, and snippets.

@wanabe
Last active August 14, 2024 10:56
Show Gist options
  • Save wanabe/f7017f9d65a773006ba91800a0557260 to your computer and use it in GitHub Desktop.
Save wanabe/f7017f9d65a773006ba91800a0557260 to your computer and use it in GitHub Desktop.

なつやすみのにっき 2024/08/14

YJIT を動かしてみたい

のでやってみます。まずビルドだけできる状態にしてみます。

これで実行すると当たり前ですがエラーになります。

# ./miniruby --yjit -e 'p 1'
thread '<unnamed>' panicked at ../yjit/src/codegen.rs:10385:56:
called `Option::unwrap()` on a `None` value
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
YJIT: yjit_init() panicked. Aborting.
Aborted

yjit/src/codegen.rs:10385gen_leave_exit() を unwrap しています。 compile_with_regs() が常に None を返すようにしているので当然こうなります。

compile_with_regs() で定型のコードを書き込むようにしてみます。

diff --git a/yjit/src/backend/riscv64/mod.rs b/yjit/src/backend/riscv64/mod.rs
index 763af5d..4c5f01d 100644
--- a/yjit/src/backend/riscv64/mod.rs
+++ b/yjit/src/backend/riscv64/mod.rs
@@ -3,6 +3,8 @@ use crate::asm::riscv64::*;
 use crate::codegen::CodePtr;
 use crate::backend::ir::*;
 
+use std::backtrace::Backtrace;
+
 // Use the x86 register type for this platform
 pub type Reg = Riscv64Reg;
 
@@ -51,7 +53,17 @@ impl Assembler
     }
 
     /// Optimize and compile the stored instructions
-    pub fn compile_with_regs(self, _cb: &mut CodeBlock, _ocb: Option<&mut OutlinedCb>, _regs: Vec<Reg>) -> Option<(CodePtr, Vec<u32>)> {
-        None
+    pub fn compile_with_regs(self, cb: &mut CodeBlock, _ocb: Option<&mut OutlinedCb>, _regs: Vec<Reg>) -> Option<(CodePtr, Vec<u32>)> {
+        println!("compile_with_regs {}", Backtrace::force_capture());
+        let start_ptr = cb.get_write_ptr();
+        let mut gc_offsets: Vec<u32> = Vec::new();
+        cb.write_bytes(&[
+            0x93, 0x85, 0x85, 0x03, // addi a1,a1,56
+            0x0c, 0xe9, // sd a1, 16(a0)
+            // retval = Qnil (a0 is retval, 8 is `nil.object_id`)
+            0x11, 0x45, // li a0, 8
+            0x82, 0x80, // ret
+        ]);
+        Some((start_ptr, gc_offsets))
     }
 }
diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs
index 072d96f..9316c4c 100644
--- a/yjit/src/codegen.rs
+++ b/yjit/src/codegen.rs
@@ -1324,6 +1324,7 @@ pub fn gen_single_block(
     }
 
     // Block compiled successfully
+    println!("Block compiled successfully {:?}", block_start_addr);
     Ok(jit.into_block(end_insn_idx, block_start_addr, end_addr, gc_offsets))
 }
 
diff --git a/yjit/src/core.rs b/yjit/src/core.rs
index cd6e649..c914bab 100644
--- a/yjit/src/core.rs
+++ b/yjit/src/core.rs
@@ -28,6 +28,8 @@ use YARVOpnd::*;
 use TempMappingKind::*;
 use crate::invariants::*;
 
+use std::backtrace::Backtrace;
+
 // Maximum number of temp value types we keep track of
 pub const MAX_TEMP_TYPES: usize = 8;
 
@@ -828,6 +830,7 @@ impl PendingBranch {
 
     // Construct the branch and wire it up in the grpah
     fn into_branch(mut self, uninit_block: BlockRef) -> BranchRef {
+        println!("into_branch {:?} {:?} {}", self.start_addr.get(), self.end_addr.get(), Backtrace::force_capture());
         // Make the branch
         let branch = Branch {
             block: uninit_block,
@@ -2703,6 +2706,7 @@ pub type PendingBranchRef = Rc<PendingBranch>;
 
 /// Create a new outgoing branch entry for a block
 fn new_pending_branch(jit: &mut JITState, gen_fn: BranchGenFn) -> PendingBranchRef {
+    println!("new_pending_branch {}", Backtrace::force_capture());
     let branch = Rc::new(PendingBranch {
         uninit_branch: Box::new(MaybeUninit::uninit()),
         gen_fn,
diff --git a/yjit/src/virtualmem.rs b/yjit/src/virtualmem.rs
index f3c0cee..46bfaba 100644
--- a/yjit/src/virtualmem.rs
+++ b/yjit/src/virtualmem.rs
@@ -202,6 +202,8 @@ impl<A: Allocator> VirtualMemory<A> {
                         std::slice::from_raw_parts_mut(mapped_region_end, alloc_size).fill(0x1E);
                     } else if cfg!(target_arch = "aarch64") {
                         // In aarch64, all zeros encodes UDF, so it's already what we want.
+                    } else if cfg!(target_arch = "riscv64") {
+                        // TODO
                     } else {
                         unreachable!("unknown arch");
                     }

ですがうまく行きません。

# ./miniruby --yjit --yjit-call-threshold=2 ../../riscv64.rb
compile_with_regs    0: yjit::backend::riscv64::<impl yjit::backend::ir::Assembler>::compile_with_regs
             at ./../yjit/src/backend/riscv64/mod.rs:57:42
   1: yjit::backend::ir::Assembler::compile
             at ./../yjit/src/backend/ir.rs:1572:19
   2: yjit::codegen::gen_leave_exit
             at ./../yjit/src/codegen.rs:922:5
   3: yjit::codegen::CodegenGlobals::init
             at ./../yjit/src/codegen.rs:10386:31
   4: yjit::yjit::yjit_init::{{closure}}
             at ./../yjit/src/yjit.rs:51:9
   5: std::panicking::try::do_call
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/std/src/panicking.rs:552:40
   6: __rust_try.llvm.13386978148669737369
   7: std::panicking::try
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/std/src/panicking.rs:516:19
   8: std::panic::catch_unwind
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/std/src/panic.rs:142:14
   9: yjit::yjit::yjit_init
             at ./../yjit/src/yjit.rs:49:18
...
  23: _start

compile_with_regs    0: yjit::backend::riscv64::<impl yjit::backend::ir::Assembler>::compile_with_regs
             at ./../yjit/src/backend/riscv64/mod.rs:57:42
   1: yjit::backend::ir::Assembler::compile
             at ./../yjit/src/backend/ir.rs:1572:19
   2: yjit::codegen::gen_leave_exception
             at ./../yjit/src/codegen.rs:956:5
   3: yjit::codegen::CodegenGlobals::init
             at ./../yjit/src/codegen.rs:10387:36
   4: yjit::yjit::yjit_init::{{closure}}
             at ./../yjit/src/yjit.rs:51:9
   5: std::panicking::try::do_call
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/std/src/panicking.rs:552:40
   6: __rust_try.llvm.13386978148669737369
   7: std::panicking::try
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/std/src/panicking.rs:516:19
   8: std::panic::catch_unwind
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/std/src/panic.rs:142:14
   9: yjit::yjit::yjit_init
             at ./../yjit/src/yjit.rs:49:18
...
  23: _start

compile_with_regs    0: yjit::backend::riscv64::<impl yjit::backend::ir::Assembler>::compile_with_regs
             at ./../yjit/src/backend/riscv64/mod.rs:57:42
   1: yjit::backend::ir::Assembler::compile
             at ./../yjit/src/backend/ir.rs:1572:19
   2: yjit::codegen::gen_stub_exit
             at ./../yjit/src/codegen.rs:719:5
   3: yjit::codegen::CodegenGlobals::init
             at ./../yjit/src/codegen.rs:10389:30
   4: yjit::yjit::yjit_init::{{closure}}
             at ./../yjit/src/yjit.rs:51:9
   5: std::panicking::try::do_call
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/std/src/panicking.rs:552:40
   6: __rust_try.llvm.13386978148669737369
   7: std::panicking::try
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/std/src/panicking.rs:516:19
   8: std::panic::catch_unwind
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/std/src/panic.rs:142:14
   9: yjit::yjit::yjit_init
             at ./../yjit/src/yjit.rs:49:18
...
  23: _start

compile_with_regs    0: yjit::backend::riscv64::<impl yjit::backend::ir::Assembler>::compile_with_regs
             at ./../yjit/src/backend/riscv64/mod.rs:57:42
   1: yjit::backend::ir::Assembler::compile
             at ./../yjit/src/backend/ir.rs:1572:19
   2: yjit::core::gen_branch_stub_hit_trampoline
             at ./../yjit/src/core.rs:2990:5
   3: yjit::codegen::CodegenGlobals::init
             at ./../yjit/src/codegen.rs:10391:42
   4: yjit::yjit::yjit_init::{{closure}}
             at ./../yjit/src/yjit.rs:51:9
   5: std::panicking::try::do_call
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/std/src/panicking.rs:552:40
   6: __rust_try.llvm.13386978148669737369
   7: std::panicking::try
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/std/src/panicking.rs:516:19
   8: std::panic::catch_unwind
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/std/src/panic.rs:142:14
   9: yjit::yjit::yjit_init
             at ./../yjit/src/yjit.rs:49:18
...
  23: _start

compile_with_regs    0: yjit::backend::riscv64::<impl yjit::backend::ir::Assembler>::compile_with_regs
             at ./../yjit/src/backend/riscv64/mod.rs:57:42
   1: yjit::backend::ir::Assembler::compile
             at ./../yjit/src/backend/ir.rs:1572:19
   2: yjit::core::gen_entry_stub_hit_trampoline
             at ./../yjit/src/core.rs:2642:5
   3: yjit::codegen::CodegenGlobals::init
             at ./../yjit/src/codegen.rs:10392:41
   4: yjit::yjit::yjit_init::{{closure}}
             at ./../yjit/src/yjit.rs:51:9
   5: std::panicking::try::do_call
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/std/src/panicking.rs:552:40
   6: __rust_try.llvm.13386978148669737369
   7: std::panicking::try
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/std/src/panicking.rs:516:19
   8: std::panic::catch_unwind
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/std/src/panic.rs:142:14
   9: yjit::yjit::yjit_init
             at ./../yjit/src/yjit.rs:49:18
...
  23: _start

compile_with_regs    0: yjit::backend::riscv64::<impl yjit::backend::ir::Assembler>::compile_with_regs
             at ./../yjit/src/backend/riscv64/mod.rs:57:42
   1: yjit::backend::ir::Assembler::compile
             at ./../yjit/src/backend/ir.rs:1572:19
   2: yjit::codegen::gen_full_cfunc_return
             at ./../yjit/src/codegen.rs:897:5
   3: yjit::codegen::CodegenGlobals::init
             at ./../yjit/src/codegen.rs:10395:31
   4: yjit::yjit::yjit_init::{{closure}}
             at ./../yjit/src/yjit.rs:51:9
   5: std::panicking::try::do_call
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/std/src/panicking.rs:552:40
   6: __rust_try.llvm.13386978148669737369
   7: std::panicking::try
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/std/src/panicking.rs:516:19
   8: std::panic::catch_unwind
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/std/src/panic.rs:142:14
   9: yjit::yjit::yjit_init
             at ./../yjit/src/yjit.rs:49:18
...
  23: _start

3
compile_with_regs    0: yjit::backend::riscv64::<impl yjit::backend::ir::Assembler>::compile_with_regs
             at ./../yjit/src/backend/riscv64/mod.rs:57:42
   1: yjit::backend::ir::Assembler::compile
             at ./../yjit/src/backend/ir.rs:1572:19
   2: yjit::codegen::gen_entry_prologue
             at ./../yjit/src/codegen.rs:1057:5
   3: yjit::core::gen_entry_point
             at ./../yjit/src/core.rs:2464:20
   4: yjit::yjit::rb_yjit_iseq_gen_entry_point::{{closure}}
             at ./../yjit/src/yjit.rs:145:49
   5: yjit::stats::with_compile_time
             at ./../yjit/src/stats.rs:1014:15
   6: rb_yjit_iseq_gen_entry_point
             at ./../yjit/src/yjit.rs:145:26
   7: rb_yjit_compile_iseq
             at ./../yjit.c:1138:25
   8: jit_compile
             at ./../vm.c:446:17
...
  18: _start

compile_with_regs    0: yjit::backend::riscv64::<impl yjit::backend::ir::Assembler>::compile_with_regs
             at ./../yjit/src/backend/riscv64/mod.rs:57:42
   1: yjit::backend::ir::Assembler::compile
             at ./../yjit/src/backend/ir.rs:1572:19
   2: yjit::codegen::gen_outlined_exit
             at ./../yjit/src/codegen.rs:801:5
   3: yjit::backend::ir::Assembler::get_side_exit
             at ./../yjit/src/backend/ir.rs:1144:33
   4: yjit::codegen::jit_ensure_block_entry_exit
             at ./../yjit/src/codegen.rs:861:26
   5: yjit::codegen::JITState::assume_no_ep_escape
             at ./../yjit/src/codegen.rs:304:12
   6: yjit::codegen::gen_getlocal_generic
             at ./../yjit/src/codegen.rs:2296:39
   7: yjit::codegen::gen_getlocal_wc0
             at ./../yjit/src/codegen.rs:2338:5
   8: yjit::codegen::gen_single_block
             at ./../yjit/src/codegen.rs:1251:22
   9: yjit::core::gen_block_series_body
             at ./../yjit/src/core.rs:2349:23
  10: yjit::core::gen_block_series
             at ./../yjit/src/core.rs:2327:18
  11: yjit::core::gen_entry_point
             at ./../yjit/src/core.rs:2469:17
  12: yjit::yjit::rb_yjit_iseq_gen_entry_point::{{closure}}
             at ./../yjit/src/yjit.rs:145:49
  13: yjit::stats::with_compile_time
             at ./../yjit/src/stats.rs:1014:15
  14: rb_yjit_iseq_gen_entry_point
             at ./../yjit/src/yjit.rs:145:26
  15: rb_yjit_compile_iseq
             at ./../yjit.c:1138:25
...
  26: _start

new_pending_branch    0: yjit::core::new_pending_branch
             at ./../yjit/src/core.rs:2709:39
   1: yjit::core::defer_compilation
             at ./../yjit/src/core.rs:3142:18
   2: yjit::codegen::gen_opt_plus
             at ./../yjit/src/codegen.rs:1619:13
   3: yjit::codegen::gen_single_block
             at ./../yjit/src/codegen.rs:1251:22
   4: yjit::core::gen_block_series_body
             at ./../yjit/src/core.rs:2349:23
   5: yjit::core::gen_block_series
             at ./../yjit/src/core.rs:2327:18
   6: yjit::core::gen_entry_point
             at ./../yjit/src/core.rs:2469:17
   7: yjit::yjit::rb_yjit_iseq_gen_entry_point::{{closure}}
             at ./../yjit/src/yjit.rs:145:49
   8: yjit::stats::with_compile_time
             at ./../yjit/src/stats.rs:1014:15
   9: rb_yjit_iseq_gen_entry_point
             at ./../yjit/src/yjit.rs:145:26
  10: rb_yjit_compile_iseq
             at ./../yjit.c:1138:25
  11: jit_compile
             at ./../vm.c:446:17
...
  21: _start

compile_with_regs    0: yjit::backend::riscv64::<impl yjit::backend::ir::Assembler>::compile_with_regs
             at ./../yjit/src/backend/riscv64/mod.rs:57:42
   1: yjit::backend::ir::Assembler::compile
             at ./../yjit/src/backend/ir.rs:1572:19
   2: yjit::core::gen_branch_stub
             at ./../yjit/src/core.rs:2953:5
   3: yjit::core::PendingBranch::set_target
             at ./../yjit/src/core.rs:816:25
   4: yjit::core::defer_compilation
             at ./../yjit/src/core.rs:3150:27
   5: yjit::codegen::gen_opt_plus
             at ./../yjit/src/codegen.rs:1619:13
   6: yjit::codegen::gen_single_block
             at ./../yjit/src/codegen.rs:1251:22
   7: yjit::core::gen_block_series_body
             at ./../yjit/src/core.rs:2349:23
   8: yjit::core::gen_block_series
             at ./../yjit/src/core.rs:2327:18
   9: yjit::core::gen_entry_point
             at ./../yjit/src/core.rs:2469:17
  10: yjit::yjit::rb_yjit_iseq_gen_entry_point::{{closure}}
             at ./../yjit/src/yjit.rs:145:49
  11: yjit::stats::with_compile_time
             at ./../yjit/src/stats.rs:1014:15
  12: rb_yjit_iseq_gen_entry_point
             at ./../yjit/src/yjit.rs:145:26
  13: rb_yjit_compile_iseq
             at ./../yjit.c:1138:25
...
  24: _start

compile_with_regs    0: yjit::backend::riscv64::<impl yjit::backend::ir::Assembler>::compile_with_regs
             at ./../yjit/src/backend/riscv64/mod.rs:57:42
   1: yjit::backend::ir::Assembler::compile
             at ./../yjit/src/backend/ir.rs:1572:19
   2: yjit::codegen::gen_single_block
             at ./../yjit/src/codegen.rs:1313:27
   3: yjit::core::gen_block_series_body
             at ./../yjit/src/core.rs:2349:23
   4: yjit::core::gen_block_series
             at ./../yjit/src/core.rs:2327:18
   5: yjit::core::gen_entry_point
             at ./../yjit/src/core.rs:2469:17
   6: yjit::yjit::rb_yjit_iseq_gen_entry_point::{{closure}}
             at ./../yjit/src/yjit.rs:145:49
   7: yjit::stats::with_compile_time
             at ./../yjit/src/stats.rs:1014:15
   8: rb_yjit_iseq_gen_entry_point
             at ./../yjit/src/yjit.rs:145:26
   9: rb_yjit_compile_iseq
             at ./../yjit.c:1138:25
...
  20: _start

Block compiled successfully CodePtr(10)
into_branch None None    0: yjit::core::PendingBranch::into_branch
             at ./../yjit/src/core.rs:833:90
   1: yjit::core::<impl yjit::codegen::JITState>::into_block::{{closure}}
             at ./../yjit/src/core.rs:1641:17
   2: core::iter::adapters::map::map_try_fold::{{closure}}
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/core/src/iter/adapters/map.rs:91:28
...
  30: _start

ruby: YJIT has panicked. More info to follow...
thread '<unnamed>' panicked at ../yjit/src/core.rs:837:47:
called `Option::unwrap()` on a `None` value
stack backtrace:
   0: rust_begin_unwind
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/std/src/panicking.rs:645:5
   1: core::panicking::panic_fmt
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/core/src/panicking.rs:72:14
   2: core::panicking::panic
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/core/src/panicking.rs:127:5
   3: core::option::Option<T>::unwrap
             at /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/core/src/option.rs:931:21
   4: yjit::core::PendingBranch::into_branch
   5: yjit::core::<impl yjit::codegen::JITState>::into_block::{{closure}}
             at ./../yjit/src/core.rs:1641:17
...
  34: _start
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
../../riscv64.rb:39: [BUG] YJIT panicked
ruby 3.4.0dev (2024-08-11) +YJIT [riscv64-linux]

-- Control frame information -----------------------------------------------
c:0003 p:0000 s:0014 e:000013 METHOD ../../riscv64.rb:39
c:0002 p:0077 s:0008 E:0004c8 EVAL   ../../riscv64.rb:44 [FINISH]
c:0001 p:0000 s:0003 E:000a00 DUMMY  [FINISH]

-- Ruby level backtrace information ----------------------------------------
../../riscv64.rb:44:in '<main>'
../../riscv64.rb:39:in 'add'

-- Threading information ---------------------------------------------------
Total ractor count: 1
Ruby thread count for this ractor: 1

-- C level backtrace information -------------------------------------------
...
/work/ruby/build/miniruby(panic+0x2a) [0x400003c5b8] library/core/src/panicking.rs:127
/work/ruby/build/miniruby(0x400035cf66) [0x400035cf66]
/work/ruby/build/miniruby(write<core::ptr::non_null::NonNull<yjit::core::Branch>>+0x0) [0x400037d568] ../yjit/src/core.rs:1641
/work/ruby/build/miniruby({closure#0}<core::ptr::non_null::NonNull<yjit::core::Branch>>) /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/alloc/src/vec/in_place_collect.rs:225
/work/ruby/build/miniruby({closure#0}<alloc::rc::Rc<yjit::core::PendingBranch, alloc::alloc::Global>, core::ptr::non_null::NonNull<yjit::core::Branch>, alloc::vec::in_place_drop::InPlaceDrop<core::ptr::non_null::NonNull<yjit::core::Branch>>, core::result::Result<alloc::vec::in_place_drop::InPlaceDrop<core::ptr::non_null::NonNull<yjit::core::Branch>>, !>, yjit::core::{impl#15}::into_block::{closure_env#0}, alloc::vec::in_place_collect::write_in_place_with_drop::{closure_env#0}<core::ptr::non_null::NonNull<yjit::core::Branch>>>) /build/rustc-Kp6Qwc/rustc-1.75.0+dfsg0ubuntu1/library/core/src/iter/adapters/map.rs:91
...

-- Other runtime information -----------------------------------------------

* Loaded script: ../../riscv64.rb

* Loaded features:

    0 enumerator.so
    1 thread.rb
    2 fiber.so
    3 rational.so
    4 complex.so
    5 ruby2_keywords.rb

* Process memory map:

...

Aborted
# 

compile_with_regs() は複数回呼び出される関数であり想定していた部分と違いそうです。 また、gen_entry_point() あたりの処理はプラットフォームごとで切り替えるようにはできていないようです。 そのため gen_opt_plus() などちゃんと用意しないで適当なコードを書き込みする方法がわかりませんでした。

ということで、RJIT のように簡単に処理を上書きするのは難しそうです。 がっつり対応するほどの熱量はないので、このあたりで諦めます。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment