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

ruby-changes:68907

From: Alan <ko1@a...>
Date: Thu, 21 Oct 2021 08:16:06 +0900 (JST)
Subject: [ruby-changes:68907] 7eef8f09c0 (master): Implement getblockparamproxy

https://git.ruby-lang.org/ruby.git/commit/?id=7eef8f09c0

From 7eef8f09c09d054b0554a304456a0bbd9df40d86 Mon Sep 17 00:00:00 2001
From: Alan Wu <XrXr@u...>
Date: Mon, 10 May 2021 17:05:12 -0400
Subject: Implement getblockparamproxy

* Implement getblockparamproxy

* Parallel runner: wait for timeout thread to terminate after killing

Or else the leak cheaker could sees the thread as running and cause test
failures in test-tool.

* Add a comment, use jne

* Comment about where 0x3 comes from
---
 bootstraptest/test_yjit.rb | 50 ++++++++++++++++++++++++++++++++++------------
 yjit_codegen.c             | 49 +++++++++++++++++++++++++++++++++++++++++++++
 yjit_core.h                |  2 ++
 3 files changed, 88 insertions(+), 13 deletions(-)

diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb
index abbe40e9e7..524b387502 100644
--- a/bootstraptest/test_yjit.rb
+++ b/bootstraptest/test_yjit.rb
@@ -858,26 +858,50 @@ assert_equal 'raised', %q{ https://github.com/ruby/ruby/blob/trunk/bootstraptest/test_yjit.rb#L858
 
 # test calling Ruby method with a block
 assert_equal '[1, 2, 42]', %q{
-def thing(a, b)
-  [a, b, yield]
-end
+  def thing(a, b)
+    [a, b, yield]
+  end
 
-def use
-  thing(1,2) { 42 }
-end
+  def use
+    thing(1,2) { 42 }
+  end
 
-use
-use
+  use
+  use
 }
 
 # test calling C method with a block
 assert_equal '[42, 42]', %q{
-def use(array, initial)
-  array.reduce(initial) { |a, b| a + b }
-end
+  def use(array, initial)
+    array.reduce(initial) { |a, b| a + b }
+  end
+
+  use([], 0)
+  [use([2, 2], 38), use([14, 14, 14], 0)]
+}
+
+# test calling block param
+assert_equal '[1, 2, 42]', %q{
+  def foo(&block)
+    block.call
+  end
 
-use([], 0)
-[use([2, 2], 38), use([14, 14, 14], 0)]
+  [foo {1}, foo {2}, foo {42}]
+}
+
+# test calling block param failing
+assert_equal '42', %q{
+  def foo(&block)
+    block.call
+  end
+
+  foo {} # warmup
+
+  begin
+    foo
+  rescue NoMethodError => e
+    42 if nil == e.receiver
+  end
 }
 
 # test calling method taking block param
diff --git a/yjit_codegen.c b/yjit_codegen.c
index 3d3e309772..e7910987c0 100644
--- a/yjit_codegen.c
+++ b/yjit_codegen.c
@@ -221,6 +221,8 @@ yjit_gen_exit(jitstate_t *jit, ctx_t *ctx, codeblock_t *cb) https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L221
 {
     uint8_t *code_ptr = cb_get_ptr(cb, cb->write_pos);
 
+    ADD_COMMENT(cb, "exit to interpreter");
+
     VALUE *exit_pc = jit->pc;
 
     // YJIT only ever patches the first instruction in an iseq
@@ -2527,6 +2529,52 @@ gen_opt_getinlinecache(jitstate_t *jit, ctx_t *ctx) https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L2529
     return YJIT_END_BLOCK;
 }
 
+// Push the explict block parameter onto the temporary stack. Part of the
+// interpreter's scheme for avoiding Proc allocations when delegating
+// explict block parameters.
+static codegen_status_t
+gen_getblockparamproxy(jitstate_t *jit, ctx_t *ctx)
+{
+    // A mirror of the interpreter code. Checking for the case
+    // where it's pushing rb_block_param_proxy.
+    uint8_t *side_exit = yjit_side_exit(jit, ctx);
+
+    // EP level
+    VALUE level = jit_get_arg(jit, 1);
+
+    if (level != 0) {
+        // Bail on non zero level to make getting the ep simple
+        return YJIT_CANT_COMPILE;
+    }
+
+    // Load environment pointer EP from CFP
+    mov(cb, REG0, member_opnd(REG_CFP, rb_control_frame_t, ep));
+
+    // Bail when VM_ENV_FLAGS(ep, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM) is non zero
+    test(cb, mem_opnd(64, REG0, SIZEOF_VALUE * VM_ENV_DATA_INDEX_FLAGS), imm_opnd(VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM));
+    jnz_ptr(cb, side_exit);
+
+    // Load the block handler for the current frame
+    // note, VM_ASSERT(VM_ENV_LOCAL_P(ep))
+    mov(cb, REG0, mem_opnd(64, REG0, SIZEOF_VALUE * VM_ENV_DATA_INDEX_SPECVAL));
+
+    // Block handler is a tagged pointer. Look at the tag. 0x03 is from VM_BH_ISEQ_BLOCK_P().
+    and(cb, REG0_8, imm_opnd(0x3));
+
+    // Bail unless VM_BH_ISEQ_BLOCK_P(bh). This also checks for null.
+    cmp(cb, REG0_8, imm_opnd(0x1));
+    jne_ptr(cb, side_exit);
+
+    // Push rb_block_param_proxy. It's a root, so no need to use jit_mov_gc_ptr.
+    mov(cb, REG0, const_ptr_opnd((void *)rb_block_param_proxy));
+    RUBY_ASSERT(!SPECIAL_CONST_P(rb_block_param_proxy));
+    x86opnd_t top = ctx_stack_push(ctx, TYPE_HEAP);
+    mov(cb, top, REG0);
+
+    return YJIT_KEEP_COMPILING;
+}
+
+
 static void
 yjit_reg_op(int opcode, codegen_fn gen_fn)
 {
@@ -2588,6 +2636,7 @@ yjit_init_codegen(void) https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L2636
     yjit_reg_op(BIN(branchunless), gen_branchunless);
     yjit_reg_op(BIN(branchnil), gen_branchnil);
     yjit_reg_op(BIN(jump), gen_jump);
+    yjit_reg_op(BIN(getblockparamproxy), gen_getblockparamproxy);
     yjit_reg_op(BIN(opt_send_without_block), gen_opt_send_without_block);
     yjit_reg_op(BIN(send), gen_send);
     yjit_reg_op(BIN(leave), gen_leave);
diff --git a/yjit_core.h b/yjit_core.h
index e44b9fe30c..948ea3bd72 100644
--- a/yjit_core.h
+++ b/yjit_core.h
@@ -17,6 +17,8 @@ https://github.com/ruby/ruby/blob/trunk/yjit_core.h#L17
 #define REG0_32 EAX
 #define REG1_32 ECX
 
+#define REG0_8 AL
+
 // Maximum number of temp value types we keep track of
 #define MAX_TEMP_TYPES 8
 
-- 
cgit v1.2.1


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

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