[前][次][番号順一覧][スレッド一覧]

ruby-changes:74323

From: Takashi <ko1@a...>
Date: Thu, 3 Nov 2022 06:20:47 +0900 (JST)
Subject: [ruby-changes:74323] 81e84e0a4d (master): YJIT: Support invokeblock (#6640)

https://git.ruby-lang.org/ruby.git/commit/?id=81e84e0a4d

From 81e84e0a4d348309d5d38311d283d049ffeeb7a2 Mon Sep 17 00:00:00 2001
From: Takashi Kokubun <takashikkbn@g...>
Date: Wed, 2 Nov 2022 09:30:48 -0700
Subject: YJIT: Support invokeblock (#6640)

* YJIT: Support invokeblock

* Update yjit/src/backend/arm64/mod.rs

* Update yjit/src/codegen.rs

Co-authored-by: Maxime Chevalier-Boisvert <maximechevalierb@g...>
---
 yjit.c                         |  14 +++-
 yjit.rb                        |   1 +
 yjit/bindgen/src/main.rs       |   5 +-
 yjit/src/backend/arm64/mod.rs  |   8 +--
 yjit/src/backend/x86_64/mod.rs |   1 +
 yjit/src/codegen.rs            | 150 +++++++++++++++++++++++++++++++++++------
 yjit/src/core.rs               |  10 +++
 yjit/src/cruby.rs              |  20 +++++-
 yjit/src/cruby_bindings.inc.rs |  11 ++-
 yjit/src/stats.rs              |   8 +++
 10 files changed, 198 insertions(+), 30 deletions(-)

diff --git a/yjit.c b/yjit.c
index 1694e1edd7..b943277d61 100644
--- a/yjit.c
+++ b/yjit.c
@@ -626,6 +626,12 @@ rb_get_iseq_body_stack_max(const rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/yjit.c#L626
     return iseq->body->stack_max;
 }
 
+bool
+rb_get_iseq_flags_has_lead(const rb_iseq_t *iseq)
+{
+    return iseq->body->param.flags.has_lead;
+}
+
 bool
 rb_get_iseq_flags_has_opt(const rb_iseq_t *iseq)
 {
@@ -669,7 +675,13 @@ rb_get_iseq_flags_has_block(const rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/yjit.c#L675
 }
 
 bool
-rb_get_iseq_flags_has_accepts_no_kwarg(const rb_iseq_t *iseq)
+rb_get_iseq_flags_ambiguous_param0(const rb_iseq_t *iseq)
+{
+    return iseq->body->param.flags.ambiguous_param0;
+}
+
+bool
+rb_get_iseq_flags_accepts_no_kwarg(const rb_iseq_t *iseq)
 {
     return iseq->body->param.flags.accepts_no_kwarg;
 }
diff --git a/yjit.rb b/yjit.rb
index ac49a30e90..bb344948eb 100644
--- a/yjit.rb
+++ b/yjit.rb
@@ -187,6 +187,7 @@ module RubyVM::YJIT https://github.com/ruby/ruby/blob/trunk/yjit.rb#L187
       $stderr.puts("***YJIT: Printing YJIT statistics on exit***")
 
       print_counters(stats, prefix: 'send_', prompt: 'method call exit reasons: ')
+      print_counters(stats, prefix: 'invokeblock_', prompt: 'invokeblock exit reasons: ')
       print_counters(stats, prefix: 'invokesuper_', prompt: 'invokesuper exit reasons: ')
       print_counters(stats, prefix: 'leave_', prompt: 'leave exit reasons: ')
       print_counters(stats, prefix: 'gbpp_', prompt: 'getblockparamproxy exit reasons: ')
diff --git a/yjit/bindgen/src/main.rs b/yjit/bindgen/src/main.rs
index 21aaec84cb..167ab2a74f 100644
--- a/yjit/bindgen/src/main.rs
+++ b/yjit/bindgen/src/main.rs
@@ -250,6 +250,7 @@ fn main() { https://github.com/ruby/ruby/blob/trunk/yjit/bindgen/src/main.rs#L250
         .blocklist_type("rb_control_frame_struct")
         .opaque_type("rb_control_frame_struct")
         .allowlist_function("rb_vm_bh_to_procval")
+        .allowlist_function("rb_vm_ep_local_ep")
         .allowlist_type("vm_special_object_type")
         .allowlist_var("VM_ENV_DATA_INDEX_SPECVAL")
         .allowlist_var("VM_ENV_DATA_INDEX_FLAGS")
@@ -353,13 +354,15 @@ fn main() { https://github.com/ruby/ruby/blob/trunk/yjit/bindgen/src/main.rs#L354
         .allowlist_function("rb_get_iseq_body_parent_iseq")
         .allowlist_function("rb_get_iseq_body_iseq_encoded")
         .allowlist_function("rb_get_iseq_body_stack_max")
+        .allowlist_function("rb_get_iseq_flags_has_lead")
         .allowlist_function("rb_get_iseq_flags_has_opt")
         .allowlist_function("rb_get_iseq_flags_has_kw")
         .allowlist_function("rb_get_iseq_flags_has_rest")
         .allowlist_function("rb_get_iseq_flags_has_post")
         .allowlist_function("rb_get_iseq_flags_has_kwrest")
         .allowlist_function("rb_get_iseq_flags_has_block")
-        .allowlist_function("rb_get_iseq_flags_has_accepts_no_kwarg")
+        .allowlist_function("rb_get_iseq_flags_ambiguous_param0")
+        .allowlist_function("rb_get_iseq_flags_accepts_no_kwarg")
         .allowlist_function("rb_get_iseq_flags_ruby2_keywords")
         .allowlist_function("rb_get_iseq_body_local_table_size")
         .allowlist_function("rb_get_iseq_body_param_keyword")
diff --git a/yjit/src/backend/arm64/mod.rs b/yjit/src/backend/arm64/mod.rs
index 0c784c0bea..ce1dd2e43c 100644
--- a/yjit/src/backend/arm64/mod.rs
+++ b/yjit/src/backend/arm64/mod.rs
@@ -165,8 +165,8 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L165
                 Opnd::Reg(_) | Opnd::InsnOut { .. } => opnd,
                 Opnd::Mem(_) => split_load_operand(asm, opnd),
                 Opnd::Imm(imm) => {
-                    if imm <= 0 {
-                        asm.load(opnd)
+                    if imm == 0 {
+                        Opnd::Reg(XZR_REG)
                     } else if (dest_num_bits == 64 &&
                                 BitmaskImmediate::try_from(imm as u64).is_ok()) ||
                             (dest_num_bits == 32 &&
@@ -1352,8 +1352,8 @@ mod tests { https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L1352
         asm.test(Opnd::Reg(X0_REG), Opnd::Imm(-7));
         asm.compile_with_num_regs(&mut cb, 1);
 
-        // Assert that a load and a test instruction were written.
-        assert_eq!(8, cb.get_write_pos());
+        // Assert that a test instruction is written.
+        assert_eq!(4, cb.get_write_pos());
     }
 
     #[test]
diff --git a/yjit/src/backend/x86_64/mod.rs b/yjit/src/backend/x86_64/mod.rs
index ac5ac0fff4..dc5f21221d 100644
--- a/yjit/src/backend/x86_64/mod.rs
+++ b/yjit/src/backend/x86_64/mod.rs
@@ -93,6 +93,7 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L93
         vec![
             RAX_REG,
             RCX_REG,
+            RDX_REG,
         ]
     }
 
diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs
index de0a2dec0f..9ec6c26f89 100644
--- a/yjit/src/codegen.rs
+++ b/yjit/src/codegen.rs
@@ -4011,6 +4011,7 @@ enum SpecVal { https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L4011
     BlockISeq(IseqPtr),
     BlockParamProxy,
     PrevEP(*const VALUE),
+    PrevEPOpnd(Opnd),
 }
 
 struct ControlFrame {
@@ -4050,17 +4051,6 @@ fn gen_push_frame( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L4051
 
     let sp = frame.sp;
 
-    let num_locals = frame.local_size;
-    if num_locals > 0 {
-        asm.comment("initialize locals");
-
-        // Initialize local variables to Qnil
-        for i in 0..num_locals {
-            let offs = (SIZEOF_VALUE as i32) * (i - num_locals - 3);
-            asm.store(Opnd::mem(64, sp, offs), Qnil.into());
-        }
-    }
-
     asm.comment("push cme, specval, frame type");
 
     // Write method entry at sp[-3]
@@ -4099,9 +4089,25 @@ fn gen_push_frame( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L4089
             let tagged_prev_ep = (prev_ep as usize) | 1;
             VALUE(tagged_prev_ep).into()
         }
+        SpecVal::PrevEPOpnd(ep_opnd) => {
+            asm.or(ep_opnd, 1.into())
+        },
     };
     asm.store(Opnd::mem(64, sp, SIZEOF_VALUE_I32 * -2), specval);
 
+    // Arm requires another register to load the immediate value of Qnil before storing it.
+    // So doing this after releasing the register for specval to avoid register spill.
+    let num_locals = frame.local_size;
+    if num_locals > 0 {
+        asm.comment("initialize locals");
+
+        // Initialize local variables to Qnil
+        for i in 0..num_locals {
+            let offs = (SIZEOF_VALUE as i32) * (i - num_locals - 3);
+            asm.store(Opnd::mem(64, sp, offs), Qnil.into());
+        }
+    }
+
     // Write env flags at sp[-1]
     // sp[-1] = frame_type;
     asm.store(Opnd::mem(64, sp, SIZEOF_VALUE_I32 * -1), frame.frame_type.into());
@@ -4522,7 +4528,7 @@ fn gen_send_bmethod( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L4528
     }
 
     let frame_type = VM_FRAME_MAGIC_BLOCK | VM_FRAME_FLAG_BMETHOD | VM_FRAME_FLAG_LAMBDA;
-    gen_send_iseq(jit, ctx, asm, ocb, iseq, ci, frame_type, Some(capture.ep), cme, block, flags, argc)
+    gen_send_iseq(jit, ctx, asm, ocb, iseq, ci, frame_type, Some(capture.ep), cme, block, flags, argc, None)
 }
 
 fn gen_send_iseq(
@@ -4538,10 +4544,10 @@ fn gen_send_iseq( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L4544
     block: Option<IseqPtr>,
     flags: u32,
     argc: i32,
+    captured_opnd: Option<Opnd>,
 ) -> CodegenStatus {
     let mut argc = argc;
 
-
     // Create a side-exit to fall back to the interpreter
     let side_exit = get_side_exit(jit, ocb, ctx);
 
@@ -4592,7 +4598,7 @@ fn gen_send_iseq( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L4598
 
     // If we have a method accepting no kwargs (**nil), exit if we have passed
     // it any kwargs.
-    if supplying_kws && unsafe { get_iseq_flags_has_accepts_no_kwarg(iseq) } {
+    if supplying_kws && unsafe { get_iseq_flags_accepts_no_kwarg(iseq) } {
         gen_counter_incr!(asm, send_iseq_complex_callee);
         return CantCompile;
     }
@@ -4997,12 +5003,17 @@ fn gen_send_iseq( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L5003
         asm.mov(ctx.stack_opnd(-1), unspec_opnd.into());
     }
 
-    // Points to the receiver operand on the stack
-    let recv = ctx.stack_opnd(argc);
+    // Points to the receiver operand on the stack unless a captured environment is used
+    let recv = match captured_opnd {
+        Some(captured_opnd) => asm.load(Opnd::mem(64, captured_opnd, 0)), // captured->self
+        _ => ctx.stack_opnd(argc),
+    };
+    let captured_self = captured_opnd.is_some();
+    let sp_offset = (argc as isize) + if captured_self { 0 } else { 1 };
 
     // Store the updated SP on the current frame (pop arguments and receiver)
     asm.comment("store caller sp");
-    let caller_sp = asm.lea(ctx.sp_opnd((SIZEOF_VALUE as isize) * -((argc as isize) + 1)));
+    let caller_sp = asm.lea(ctx.sp_opnd((SIZEO (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]