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

ruby-changes:68817

From: Maxime <ko1@a...>
Date: Thu, 21 Oct 2021 08:14:04 +0900 (JST)
Subject: [ruby-changes:68817] 2e8db8c35e (master): Update ec->cfp->pc when hitting a stub.

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

From 2e8db8c35e5bb00a2a27657e2d091edf9e27cacd Mon Sep 17 00:00:00 2001
From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...>
Date: Tue, 2 Mar 2021 12:03:11 -0500
Subject: Update ec->cfp->pc when hitting a stub.

---
 ujit_codegen.c | 27 +++++++++++++--------------
 ujit_core.c    |  6 +++++-
 ujit_iface.c   | 10 ++++++++++
 ujit_iface.h   |  1 +
 4 files changed, 29 insertions(+), 15 deletions(-)

diff --git a/ujit_codegen.c b/ujit_codegen.c
index e67d15c96b..05114f85af 100644
--- a/ujit_codegen.c
+++ b/ujit_codegen.c
@@ -66,8 +66,10 @@ jit_mov_gc_ptr(jitstate_t* jit, codeblock_t* cb, x86opnd_t reg, VALUE ptr) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L66
 {
     RUBY_ASSERT(reg.type == OPND_REG && reg.num_bits == 64);
 
+    // Load the pointer constant into the specified register
     mov(cb, reg, const_ptr_opnd((void*)ptr));
-    // The pointer immediate is encoded as the last part of the mov written out.
+
+    // The pointer immediate is encoded as the last part of the mov written out
     uint32_t ptr_offset = cb->write_pos - sizeof(VALUE);
 
     if (!SPECIAL_CONST_P(ptr)) {
@@ -147,7 +149,7 @@ ujit_side_exit(jitstate_t* jit, ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L149
     // Write back the old instruction at the exit PC
     // Otherwise the interpreter may jump right back to the
     // JITted code we're trying to exit
-    VALUE* exit_pc = &jit->iseq->body->iseq_encoded[jit->insn_idx];
+    VALUE* exit_pc = iseq_pc_at_idx(jit->iseq, jit->insn_idx);
     int exit_opcode = opcode_at_pc(jit->iseq, exit_pc);
     void* handler_addr = (void*)handler_table[exit_opcode];
     mov(ocb, RAX, const_ptr_opnd(exit_pc));
@@ -212,7 +214,6 @@ ujit_gen_block(ctx_t* ctx, block_t* block, rb_execution_context_t* ec) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L214
 
     const rb_iseq_t *iseq = block->blockid.iseq;
     uint32_t insn_idx = block->blockid.idx;
-    VALUE *encoded = iseq->body->iseq_encoded;
 
     // NOTE: if we are ever deployed in production, we
     // should probably just log an error and return NULL here,
@@ -227,7 +228,7 @@ ujit_gen_block(ctx_t* ctx, block_t* block, rb_execution_context_t* ec) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L228
     // Initialize a JIT state object
     jitstate_t jit = {
         block,
-        block->blockid.iseq,
+        iseq,
         0,
         0,
         ec
@@ -239,9 +240,8 @@ ujit_gen_block(ctx_t* ctx, block_t* block, rb_execution_context_t* ec) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L240
     // For each instruction to compile
     for (;;) {
         // Set the current instruction
-        RUBY_ASSERT(insn_idx < iseq->body->iseq_size);
         jit.insn_idx = insn_idx;
-        jit.pc = &encoded[insn_idx];
+        jit.pc = iseq_pc_at_idx(iseq, insn_idx);
 
         // Get the current opcode
         int opcode = jit_get_opcode(&jit);
@@ -251,7 +251,7 @@ ujit_gen_block(ctx_t* ctx, block_t* block, rb_execution_context_t* ec) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L251
         if (!rb_st_lookup(gen_fns, opcode, (st_data_t*)&gen_fn)) {
             // If we reach an unknown instruction,
             // exit to the interpreter and stop compiling
-            ujit_gen_exit(&jit, ctx, cb, &encoded[insn_idx]);
+            ujit_gen_exit(&jit, ctx, cb, jit.pc);
             break;
         }
 
@@ -273,7 +273,7 @@ ujit_gen_block(ctx_t* ctx, block_t* block, rb_execution_context_t* ec) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L273
         // If we can't compile this instruction
         // exit to the interpreter and stop compiling
         if (status == UJIT_CANT_COMPILE) {
-            ujit_gen_exit(&jit, ctx, cb, &encoded[insn_idx]);
+            ujit_gen_exit(&jit, ctx, cb, jit.pc);
             break;
         }
 
@@ -295,12 +295,11 @@ ujit_gen_block(ctx_t* ctx, block_t* block, rb_execution_context_t* ec) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L295
     if (UJIT_DUMP_MODE >= 2) {
         // Dump list of compiled instrutions
         fprintf(stderr, "Compiled the following for iseq=%p:\n", (void *)iseq);
-        VALUE *pc = &encoded[block->blockid.idx];
-        VALUE *end_pc = &encoded[insn_idx];
-        while (pc < end_pc) {
-            int opcode = opcode_at_pc(iseq, pc);
-            fprintf(stderr, "  %04td %s\n", pc - encoded, insn_name(opcode));
-            pc += insn_len(opcode);
+        for (uint32_t idx = block->blockid.idx; idx < insn_idx;)
+        {
+            int opcode = opcode_at_pc(iseq, iseq_pc_at_idx(iseq, idx));
+            fprintf(stderr, "  %04d %s\n", idx, insn_name(opcode));
+            idx += insn_len(opcode);
         }
     }
 }
diff --git a/ujit_core.c b/ujit_core.c
index 32060fa38b..5690734d30 100644
--- a/ujit_core.c
+++ b/ujit_core.c
@@ -373,6 +373,10 @@ uint8_t* branch_stub_hit(uint32_t branch_idx, uint32_t target_idx, rb_execution_ https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L373
     //fprintf(stderr, "\nstub hit, branch idx: %d, target idx: %d\n", branch_idx, target_idx);
     //fprintf(stderr, "blockid.iseq=%p, blockid.idx=%d\n", target.iseq, target.idx);
 
+    // Update the PC in the current CFP, because it
+    // may be out of sync in JITted code
+    ec->cfp->pc = iseq_pc_at_idx(target.iseq, target.idx);
+
     // If either of the target blocks will be placed next
     if (cb->write_pos == branch->end_pos)
     {
@@ -688,7 +692,7 @@ invalidate_block_version(block_t* block) https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L692
     uint32_t idx = block->blockid.idx;
     // FIXME: the following says "if", but it's unconditional.
     // If the block is an entry point, it needs to be unmapped from its iseq
-    VALUE* entry_pc = &iseq->body->iseq_encoded[idx];
+    VALUE* entry_pc = iseq_pc_at_idx(iseq, idx);
     int entry_opcode = opcode_at_pc(iseq, entry_pc);
 
     // TODO: unmap_addr2insn in ujit_iface.c? Maybe we can write a function to encompass this logic?
diff --git a/ujit_iface.c b/ujit_iface.c
index 70dae7dfdb..b5cdfee0cf 100644
--- a/ujit_iface.c
+++ b/ujit_iface.c
@@ -62,6 +62,16 @@ cb_write_post_call_bytes(codeblock_t* cb) https://github.com/ruby/ruby/blob/trunk/ujit_iface.c#L62
         cb_write_byte(cb, ujit_with_ec_post_call_bytes[i]);
 }
 
+// Get the PC for a given index in an iseq
+VALUE *iseq_pc_at_idx(const rb_iseq_t *iseq, uint32_t insn_idx)
+{
+    RUBY_ASSERT(iseq != NULL);
+    RUBY_ASSERT(insn_idx < iseq->body->iseq_size);
+    VALUE *encoded = iseq->body->iseq_encoded;
+    VALUE *pc = &encoded[insn_idx];
+    return pc;
+}
+
 // Keep track of mapping from instructions to generated code
 // See comment for rb_encoded_insn_data in iseq.c
 void
diff --git a/ujit_iface.h b/ujit_iface.h
index accaa1a37f..c1f34ed459 100644
--- a/ujit_iface.h
+++ b/ujit_iface.h
@@ -28,6 +28,7 @@ RUBY_EXTERN int64_t rb_compiled_iseq_count; https://github.com/ruby/ruby/blob/trunk/ujit_iface.h#L28
 void cb_write_pre_call_bytes(codeblock_t* cb);
 void cb_write_post_call_bytes(codeblock_t* cb);
 
+VALUE *iseq_pc_at_idx(const rb_iseq_t *iseq, uint32_t insn_idx);
 void map_addr2insn(void *code_ptr, int insn);
 int opcode_at_pc(const rb_iseq_t *iseq, const VALUE *pc);
 
-- 
cgit v1.2.1


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

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