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

ruby-changes:69613

From: John <ko1@a...>
Date: Sat, 6 Nov 2021 05:54:38 +0900 (JST)
Subject: [ruby-changes:69613] 9cc2c74b83 (master): YJIT: Implement checkkeyword (#5083)

https://git.ruby-lang.org/ruby.git/commit/?id=9cc2c74b83

From 9cc2c74b8381670f584ed31b81aedb66c8f61b34 Mon Sep 17 00:00:00 2001
From: John Hawthorn <john@h...>
Date: Fri, 5 Nov 2021 13:54:23 -0700
Subject: YJIT: Implement checkkeyword (#5083)

Co-authored-by: John Crepezzi <john.crepezzi@g...>

Co-authored-by: John Crepezzi <john.crepezzi@g...>
---
 test/ruby/test_yjit.rb | 10 ++++++++++
 yjit_codegen.c         | 40 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+)

diff --git a/test/ruby/test_yjit.rb b/test/ruby/test_yjit.rb
index ad40ad1988c..f0d899e9088 100644
--- a/test/ruby/test_yjit.rb
+++ b/test/ruby/test_yjit.rb
@@ -397,6 +397,16 @@ class TestYJIT < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_yjit.rb#L397
     RUBY
   end
 
+  def test_checkkeyword
+    assert_compiles(<<~'RUBY', insns: %i[checkkeyword], result: [2, 5])
+      def foo(foo: 1+1)
+        foo
+      end
+
+      [foo, foo(foo: 5)]
+    RUBY
+  end
+
   def test_invokebuiltin
     assert_compiles(<<~RUBY)
       def foo(obj)
diff --git a/yjit_codegen.c b/yjit_codegen.c
index ac79ce1e75e..db27c52ed95 100644
--- a/yjit_codegen.c
+++ b/yjit_codegen.c
@@ -1359,6 +1359,45 @@ gen_setlocal_wc0(jitstate_t *jit, ctx_t *ctx, codeblock_t *cb) https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L1359
     return YJIT_KEEP_COMPILING;
 }
 
+// Push Qtrue or Qfalse depending on whether the given keyword was supplied by
+// the caller
+static codegen_status_t
+gen_checkkeyword(jitstate_t *jit, ctx_t *ctx, codeblock_t *cb)
+{
+    // When a keyword is unspecified past index 32, a hash will be used
+    // instead. This can only happen in iseqs taking more than 32 keywords.
+    if (jit->iseq->body->param.keyword->num >= 32) {
+        return YJIT_CANT_COMPILE;
+    }
+
+    // The EP offset to the undefined bits local
+    int32_t bits_offset = (int32_t)jit_get_arg(jit, 0);
+
+    // The index of the keyword we want to check
+    int32_t index = (int32_t)jit_get_arg(jit, 1);
+
+    // Load environment pointer EP
+    gen_get_ep(cb, REG0, 0);
+
+    // VALUE kw_bits = *(ep - bits);
+    x86opnd_t bits_opnd = mem_opnd(64, REG0, sizeof(VALUE) * -bits_offset);
+
+    // unsigned int b = (unsigned int)FIX2ULONG(kw_bits);
+    // if ((b & (0x01 << idx))) {
+    //
+    // We can skip the FIX2ULONG conversion by shifting the bit we test
+    int64_t bit_test = 0x01 << (index + 1);
+    test(cb, bits_opnd, imm_opnd(bit_test));
+    mov(cb, REG0, imm_opnd(Qfalse));
+    mov(cb, REG1, imm_opnd(Qtrue));
+    cmovz(cb, REG0, REG1);
+
+    x86opnd_t stack_ret = ctx_stack_push(ctx, TYPE_IMM);
+    mov(cb, stack_ret, REG0);
+
+    return YJIT_KEEP_COMPILING;
+}
+
 static codegen_status_t
 gen_setlocal_generic(jitstate_t *jit, ctx_t *ctx, uint32_t local_idx, uint32_t level)
 {
@@ -4754,6 +4793,7 @@ yjit_init_codegen(void) https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L4793
     yjit_reg_op(BIN(setinstancevariable), gen_setinstancevariable);
     yjit_reg_op(BIN(defined), gen_defined);
     yjit_reg_op(BIN(checktype), gen_checktype);
+    yjit_reg_op(BIN(checkkeyword), gen_checkkeyword);
     yjit_reg_op(BIN(opt_lt), gen_opt_lt);
     yjit_reg_op(BIN(opt_le), gen_opt_le);
     yjit_reg_op(BIN(opt_ge), gen_opt_ge);
-- 
cgit v1.2.1


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

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