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

ruby-changes:68727

From: Maxime <ko1@a...>
Date: Thu, 21 Oct 2021 08:12:37 +0900 (JST)
Subject: [ruby-changes:68727] 2e561ff255 (master): Restore interpreter regs in ujit hook. Implement leave bytecode.

https://git.ruby-lang.org/ruby.git/commit/?id=2e561ff255

From 2e561ff255ea69e50f2d53240332cfd96463ef06 Mon Sep 17 00:00:00 2001
From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...>
Date: Thu, 28 Jan 2021 16:58:20 -0500
Subject: Restore interpreter regs in ujit hook. Implement leave bytecode.

---
 iseq.c                                             | 13 +------
 iseq.h                                             |  4 +-
 tool/ruby_vm/models/micro_jit.rb                   | 10 ++---
 .../models/micro_jit/example_instructions.rb       | 12 ++----
 tool/ruby_vm/views/vm.inc.erb                      |  9 +++--
 ujit_codegen.c                                     | 44 +++++++++++++++++++++-
 vm_exec.h                                          |  2 +-
 7 files changed, 59 insertions(+), 35 deletions(-)

diff --git a/iseq.c b/iseq.c
index d4d5261c3c..958f7f847f 100644
--- a/iseq.c
+++ b/iseq.c
@@ -3485,21 +3485,12 @@ trace_set_i(void *vstart, void *vend, size_t stride, void *data) https://github.com/ruby/ruby/blob/trunk/iseq.c#L3485
     return 0;
 }
 
-VALUE *
-rb_ujit_empty_func(rb_control_frame_t *cfp)
+void
+rb_ujit_empty_func_with_ec(rb_control_frame_t *cfp, rb_execution_context_t *ec)
 {
-    // okay, not really empty, so maybe think of another name.
     // it's put in this file instead of say, compile.c to dodge long C compile time.
     // it just needs to be in a different unit from vm.o so the compiler can't see the definition
     // and is forced to emit a call that respects the calling convention.
-    return NULL;
-}
-
-VALUE *
-rb_ujit_empty_func_with_ec(rb_control_frame_t *cfp, rb_execution_context_t *ec)
-{
-    // see rb_ujit_empty_func
-    return NULL;
 }
 
 void
diff --git a/iseq.h b/iseq.h
index cd939a0684..8275bab575 100644
--- a/iseq.h
+++ b/iseq.h
@@ -315,9 +315,7 @@ VALUE rb_iseq_defined_string(enum defined_type type); https://github.com/ruby/ruby/blob/trunk/iseq.h#L315
 /* vm.c */
 VALUE rb_iseq_local_variables(const rb_iseq_t *iseq);
 
-NOINLINE(VALUE *rb_ujit_empty_func(rb_control_frame_t *cfp));
-NOINLINE(VALUE *rb_ujit_empty_func_with_ec(rb_control_frame_t *cfp, rb_execution_context_t *ec));
-
+NOINLINE(void rb_ujit_empty_func_with_ec(rb_control_frame_t *cfp, rb_execution_context_t *ec));
 
 RUBY_SYMBOL_EXPORT_END
 
diff --git a/tool/ruby_vm/models/micro_jit.rb b/tool/ruby_vm/models/micro_jit.rb
index 9bbce73150..5e376ebb3a 100644
--- a/tool/ruby_vm/models/micro_jit.rb
+++ b/tool/ruby_vm/models/micro_jit.rb
@@ -176,10 +176,9 @@ module RubyVM::MicroJIT https://github.com/ruby/ruby/blob/trunk/tool/ruby_vm/models/micro_jit.rb#L176
       disassemble(handler_offset)
     end
 
-    def make_result(success, without_pc, with_pc)
+    def make_result(success, with_pc)
       [success ? 1 : 0,
        [
-         ['ujit_without_ec', without_pc],
          ['ujit_with_ec', with_pc],
        ]
       ]
@@ -193,19 +192,18 @@ module RubyVM::MicroJIT https://github.com/ruby/ruby/blob/trunk/tool/ruby_vm/models/micro_jit.rb#L192
       when :linux
         linux_scrape(instruction_id)
       else
-        raise 'Unkonwn platform. Only Mach-O on macOS and ELF on Linux are supported'
+        raise 'Unknown platform. Only Mach-O on macOS and ELF on Linux are supported'
       end
     end
 
     def scrape
-      without_ec = scrape_instruction(RubyVM::Instructions.find_index { |insn| insn.name == 'ujit_call_example' })
       with_ec = scrape_instruction(RubyVM::Instructions.find_index { |insn| insn.name == 'ujit_call_example_with_ec' })
-      make_result(true, without_ec, with_ec)
+      make_result(true, with_ec)
     rescue => e
       print_warning("scrape failed: #{e.message}")
       int3 = '0xcc'
       failure_result = ScrapeResult.new(int3, int3, ['int3'])
-      make_result(false, failure_result, failure_result)
+      make_result(false, failure_result)
     end
 
     def print_warning(text)
diff --git a/tool/ruby_vm/models/micro_jit/example_instructions.rb b/tool/ruby_vm/models/micro_jit/example_instructions.rb
index 111346f6e9..23ecf72a3b 100644
--- a/tool/ruby_vm/models/micro_jit/example_instructions.rb
+++ b/tool/ruby_vm/models/micro_jit/example_instructions.rb
@@ -13,11 +13,10 @@ https://github.com/ruby/ruby/blob/trunk/tool/ruby_vm/models/micro_jit/example_instructions.rb#L13
 class RubyVM::MicroJIT::ExampleInstructions
   include RubyVM::CEscape
 
-  attr_reader :name, :call_line
+  attr_reader :name
 
-  def initialize(name, call_line)
+  def initialize(name)
     @name = name
-    @call_line = call_line
   end
 
   def pretty_name
@@ -64,12 +63,7 @@ class RubyVM::MicroJIT::ExampleInstructions https://github.com/ruby/ruby/blob/trunk/tool/ruby_vm/models/micro_jit/example_instructions.rb#L63
     false
   end
 
-  @all_examples = [
-    new('ujit_call_example', 'reg_pc = rb_ujit_empty_func(GET_CFP());'),
-    new('ujit_call_example_with_ec', 'reg_pc = rb_ujit_empty_func_with_ec(GET_CFP(), ec);')
-  ]
-
   def self.to_a
-    @all_examples
+    [new('ujit_call_example_with_ec')]
   end
 end
diff --git a/tool/ruby_vm/views/vm.inc.erb b/tool/ruby_vm/views/vm.inc.erb
index 235eb30b11..57a860efcf 100644
--- a/tool/ruby_vm/views/vm.inc.erb
+++ b/tool/ruby_vm/views/vm.inc.erb
@@ -26,15 +26,16 @@ https://github.com/ruby/ruby/blob/trunk/tool/ruby_vm/views/vm.inc.erb#L26
 % end
 %
 % RubyVM::MicroJIT::ExampleInstructions.to_a.each do |insn|
-INSN_ENTRY(<%= insn.name %>)
+INSN_ENTRY(ujit_call_example_with_ec)
 {
-    START_OF_ORIGINAL_INSN(<%= insn.name %>);
+    START_OF_ORIGINAL_INSN(ujit_call_example_with_ec);
 #if USE_MACHINE_REGS
     // assumes USE_MACHINE_REGS, aka reg_pc setup,
     // aka #define SET_PC(x) (reg_cfp->pc = reg_pc = (x))
-    <%= insn.call_line %>
+    rb_ujit_empty_func_with_ec(GET_CFP(), ec);
+    RESTORE_REGS();
 #endif
-    END_INSN(<%= insn.name %>);
+    END_INSN(ujit_call_example_with_ec);
 }
 % end
 %
diff --git a/ujit_codegen.c b/ujit_codegen.c
index 43da3e6473..7c7457aea3 100644
--- a/ujit_codegen.c
+++ b/ujit_codegen.c
@@ -371,7 +371,7 @@ gen_setlocal_wc0(jitstate_t* jit, ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L371
     mov(cb, REG0, member_opnd(REG_CFP, rb_control_frame_t, ep));
 
     // flags & VM_ENV_FLAG_WB_REQUIRED
-    x86opnd_t flags_opnd = mem_opnd(64, REG0, 8 * VM_ENV_DATA_INDEX_FLAGS);
+    x86opnd_t flags_opnd = mem_opnd(64, REG0, sizeof(VALUE) * VM_ENV_DATA_INDEX_FLAGS);
     test(cb, flags_opnd, imm_opnd(VM_ENV_FLAG_WB_REQUIRED));
 
     // Create a size-exit to fall back to the interpreter
@@ -1062,6 +1062,47 @@ gen_opt_send_without_block(jitstate_t* jit, ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L1062
     return true;
 }
 
+static bool
+gen_leave(jitstate_t* jit, ctx_t* ctx)
+{
+    // Only the return value should be on the stack
+    RUBY_ASSERT(ctx->stack_size == 1);
+
+    // Create a size-exit to fall back to the interpreter
+    uint8_t* side_exit = ujit_side_exit(jit, ctx);
+
+    // Load environment pointer EP from CFP
+    mov(cb, REG0, member_opnd(REG_CFP, rb_control_frame_t, ep));
+
+    // flags & VM_FRAME_FLAG_FINISH
+    x86opnd_t flags_opnd = mem_opnd(64, REG0, sizeof(VALUE) * VM_ENV_DATA_INDEX_FLAGS);
+    test(cb, flags_opnd, imm_opnd(VM_FRAME_FLAG_FINISH));
+
+    // if (flags & VM_FRAME_FLAG_FINISH) != 0
+    jnz_ptr(cb, side_exit);
+
+    // TODO:
+    // RUBY_VM_CHECK_INTS(ec);
+
+    // Load the return value
+    mov(cb, REG0, ctx_stack_pop(ctx, 1));
+
+    // Pop the current CFP (ec->cfp++)
+    // Note: the return PC is already in the previous CFP
+    add(cb, REG_CFP, imm_opnd(sizeof(rb_control_frame_t)));
+    mov(cb, member_opnd(REG_EC, rb_execution_context_t, cfp), REG_CFP);
+
+    // Push the return value on the caller frame
+    mov(cb, REG1, member_opnd(REG_CFP, rb_control_frame_t, sp));
+    mov(cb, mem_opnd(64, REG1, 0), REG0);
+    add(cb, member_opnd(REG_CFP, rb_control_frame_t, sp), imm_opnd(SIZEOF_VALUE));
+
+    // Write the post call bytes
+    cb_write_post_call_bytes(cb);
+
+    return true;
+}
+
 void ujit_reg_op(int opcode, codegen_fn gen_fn, bool is_branch)
 {
     // Check that the op wasn't previously registered
@@ -1111,4 +1152,5 @@ ujit_init_codegen(void) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L1152
     ujit_reg_op(BIN(branchunless), gen_branchunless, true);
     ujit_reg_op(BIN(jump), gen_jump, true);
     ujit_reg_op(BIN(opt_send_without_block), gen_opt_send_without_block, true);
+    ujit_reg_op(BIN(leave), gen_leave, true);
 }
diff --git a/vm_exec.h b/vm_exec.h
index 998dbfb48d..1e12f5cbe3 100644
--- a/vm_exec.h
+++ b/vm_exec.h
@@ -81,7 +81,7 @@ error ! https://github.com/ruby/ruby/blob/trunk/vm_exec.h#L81
                         RSTRING_PTR(rb_iseq_path(reg_cfp->iseq)), \
                         rb_iseq_line_no(reg_cfp->iseq, reg_pc - reg_cfp->iseq->body->iseq_encoded)); \
   } \
-  if (USE_INSNS_COUNTER && BIN(insn) != BIN(ujit_call_example)) vm_insns_counter_count_insn(BIN(insn));
+  if (USE_INSNS_COUNTER && BIN(insn) != BIN(ujit_call_example_with_ec)) vm_insns_counter_count_insn(BIN(insn));
 
 #define INSN_DISPATCH_SIG(insn)
 
-- 
cgit v1.2.1


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

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