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

ruby-changes:68698

From: Maxime <ko1@a...>
Date: Thu, 21 Oct 2021 08:12:27 +0900 (JST)
Subject: [ruby-changes:68698] 2cf32e5505 (master): Refactor ujit logic for generating iseq entry points

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

From 2cf32e5505d8da85f31df3a0bff7b0fd38054503 Mon Sep 17 00:00:00 2001
From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...>
Date: Wed, 13 Jan 2021 14:14:16 -0500
Subject: Refactor ujit logic for generating iseq entry points

---
 ujit_codegen.c | 53 +++++++++++++++++++++--------------------------------
 ujit_codegen.h |  7 ++-----
 ujit_core.c    | 27 ++++++++++++++++++++++++---
 ujit_core.h    |  1 +
 ujit_iface.c   | 10 +++++++---
 5 files changed, 55 insertions(+), 43 deletions(-)

diff --git a/ujit_codegen.c b/ujit_codegen.c
index 4833e4ab1f..9a17ca942a 100644
--- a/ujit_codegen.c
+++ b/ujit_codegen.c
@@ -48,18 +48,6 @@ jit_get_arg(jitstate_t* jit, size_t arg_idx) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L48
     return *(jit->pc + arg_idx + 1);
 }
 
-/**
-Generate code to enter from the Ruby interpreter into ujit code
-*/
-static void
-ujit_gen_entry(codeblock_t* cb)
-{
-    cb_write_pre_call_bytes(cb);
-
-    // Load the current SP from the CFP into REG_SP
-    mov(cb, REG_SP, member_opnd(REG_CFP, rb_control_frame_t, sp));
-}
-
 /**
 Generate an inline exit to return to the interpreter
 */
@@ -110,10 +98,11 @@ ujit_side_exit(jitstate_t* jit, ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L98
 }
 
 /*
-Compile an interpreter entry point to be inserted into an iseq
+Compile an interpreter entry block to be inserted into an iseq
 Returns `NULL` if compilation fails.
 */
-uint8_t* ujit_compile_entry(const rb_iseq_t *iseq, uint32_t insn_idx)
+uint8_t*
+ujit_gen_entry(version_t* version)
 {
     assert (cb != NULL);
 
@@ -127,36 +116,37 @@ uint8_t* ujit_compile_entry(const rb_iseq_t *iseq, uint32_t insn_idx) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L116
     uint8_t *code_ptr = cb_get_ptr(cb, cb->write_pos);
 
     // Write the interpreter entry prologue
-    ujit_gen_entry(cb);
+    cb_write_pre_call_bytes(cb);
 
-    // Create codegen context
-    ctx_t ctx = { 0 };
+    // Load the current SP from the CFP into REG_SP
+    mov(cb, REG_SP, member_opnd(REG_CFP, rb_control_frame_t, sp));
 
     // Compile the block starting at this instruction
-    uint32_t num_instrs = ujit_compile_block(iseq, insn_idx, &ctx);
+    uint32_t num_instrs = ujit_gen_code(version);
 
+    // FIXME: can we eliminate this check?
     // If no instructions were compiled
     if (num_instrs == 0) {
         return NULL;
     }
 
-    // Get the first opcode in the sequence
-    VALUE *encoded = iseq->body->iseq_encoded;
-    int first_opcode = opcode_at_pc(iseq, &encoded[insn_idx]);
-
-    // Map the code address to the corresponding opcode
-    map_addr2insn(code_ptr, first_opcode);
-
     return code_ptr;
 }
 
 /*
-Compile a sequence of bytecode instructions starting at `insn_idx`.
+Compile a sequence of bytecode instructions
 */
 uint32_t
-ujit_compile_block(/*version_t* version,*/ const rb_iseq_t *iseq, uint32_t insn_idx, ctx_t* ctx)
+ujit_gen_code(version_t* version)
 {
     assert (cb != NULL);
+
+    // Copy the version's context to avoid mutating it
+    ctx_t ctx_copy = version->ctx;
+    ctx_t* ctx = &ctx_copy;
+
+    const rb_iseq_t *iseq = version->blockid.iseq;
+    uint32_t insn_idx = version->blockid.idx;
     VALUE *encoded = iseq->body->iseq_encoded;
 
     // NOTE: if we are ever deployed in production, we
@@ -174,9 +164,8 @@ ujit_compile_block(/*version_t* version,*/ const rb_iseq_t *iseq, uint32_t insn_ https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L164
 
     // Initialize JIT state object
     jitstate_t jit = {
-        NULL,
-        iseq,
-        insn_idx
+        version,
+        iseq
     };
 
     uint32_t num_instrs = 0;
@@ -219,7 +208,7 @@ ujit_compile_block(/*version_t* version,*/ const rb_iseq_t *iseq, uint32_t insn_ https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L208
         }
     }
 
-    // If the last instruction compiled did not properly terminate the block
+    // If the last instruction compiled did not terminate the block
     // Generate code to exit to the interpreter
     if (!p_last_op || !p_last_op->is_branch) {
         ujit_gen_exit(&jit, ctx, cb, &encoded[insn_idx]);
@@ -228,7 +217,7 @@ ujit_compile_block(/*version_t* version,*/ const rb_iseq_t *iseq, uint32_t insn_ https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L217
     if (UJIT_DUMP_MODE >= 2) {
         // Dump list of compiled instrutions
         fprintf(stderr, "Compiled the following for iseq=%p:\n", (void *)iseq);
-        VALUE *pc = &encoded[jit.start_idx];
+        VALUE *pc = &encoded[version->blockid.idx];
         VALUE *end_pc = &encoded[insn_idx];
         while (pc < end_pc) {
             int opcode = opcode_at_pc(iseq, pc);
diff --git a/ujit_codegen.h b/ujit_codegen.h
index d01a73bde0..0564c594d3 100644
--- a/ujit_codegen.h
+++ b/ujit_codegen.h
@@ -17,9 +17,6 @@ typedef struct JITState https://github.com/ruby/ruby/blob/trunk/ujit_codegen.h#L17
     // Instruction sequence this is associated with
     const rb_iseq_t *iseq;
 
-    // Index in the iseq of the opcode we are replacing
-    const uint32_t start_idx;
-
     // Index of the current instruction being compiled
     uint32_t insn_idx;
 
@@ -43,9 +40,9 @@ typedef struct OpDesc https://github.com/ruby/ruby/blob/trunk/ujit_codegen.h#L40
 
 } opdesc_t;
 
-uint8_t* ujit_compile_entry(const rb_iseq_t *iseq, uint32_t insn_idx);
+uint8_t* ujit_gen_entry(version_t* version);
 
-uint32_t ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, ctx_t* ctx);
+uint32_t ujit_gen_code(version_t* version);
 
 void ujit_init_codegen(void);
 
diff --git a/ujit_core.c b/ujit_core.c
index c316675185..922ea4f1e8 100644
--- a/ujit_core.c
+++ b/ujit_core.c
@@ -84,7 +84,6 @@ version_t* find_block_version(blockid_t block, const ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L84
 
     return NULL;
 }
-
 // Compile a new block version immediately
 version_t* gen_block_version(blockid_t blockid, const ctx_t* ctx)
 {
@@ -94,9 +93,8 @@ version_t* gen_block_version(blockid_t blockid, const ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L93
     memcpy(&p_version->ctx, ctx, sizeof(ctx_t));
 
     // Compile the block version
-    ctx_t ctx_copy = *ctx;
     p_version->start_pos = cb->write_pos;
-    ujit_compile_block(blockid.iseq, blockid.idx, &ctx_copy);
+    ujit_gen_code(p_version);
     p_version->end_pos = cb->write_pos;
 
     // Keep track of the new block version
@@ -105,6 +103,29 @@ version_t* gen_block_version(blockid_t blockid, const ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L103
     return p_version;
 }
 
+// Generate a block version that is an entry point inserted into an iseq
+uint8_t* gen_entry_point(const rb_iseq_t *iseq, uint32_t insn_idx)
+{
+    // Allocate a version object
+    version_t* p_version = malloc(sizeof(version_t));
+    blockid_t blockid = { iseq, insn_idx };
+    memcpy(&p_version->blockid, &blockid, sizeof(blockid_t));
+
+    // The entry context makes no assumptions about types
+    ctx_t ctx = { 0 };
+    memcpy(&p_version->ctx, &ctx, sizeof(ctx_t));
+
+    // Compile the block version
+    p_version->start_pos = cb->write_pos;
+    uint8_t* code_ptr = ujit_gen_entry(p_version);
+    p_version->end_pos = cb->write_pos;
+
+    // Keep track of the new block version
+    st_insert(version_tbl, (st_data_t)&p_version->blockid, (st_data_t)p_version);
+
+    return code_ptr;
+}
+
 // Called by the generated code when a branch stub is executed
 // Triggers compilation of branches and code patching
 uint8_t* branch_stub_hit(uint32_t branch_idx, uint32_t target_idx)
diff --git a/ujit_core.h b/ujit_core.h
index 07a18ed727..065bafe786 100644
--- a/ujit_core.h
+++ b/ujit_core.h
@@ -112,6 +112,7 @@ x86opnd_t ctx_stack_opnd(ctx_t* ctx, int32_t idx); https://github.com/ruby/ruby/blob/trunk/ujit_core.h#L112
 
 version_t* find_block_version(blockid_t block, const ctx_t* ctx);
 version_t* gen_block_version(blockid_t block, const ctx_t* ctx);
+uint8_t*  gen_entry_point(const rb_iseq_t *iseq, uint32_t insn_idx);
 
 void gen_branch(
     const ctx_t* src_ctx,
diff --git a/ujit_iface.c b/ujit_iface.c
index 46d4bc4864..85be128057 100644
--- a/ujit_iface.c
+++ b/ujit_iface.c
@@ -237,10 +237,14 @@ rb_ujit_compile_iseq(const rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/ujit_iface.c#L237
     VALUE *encoded = (VALUE *)iseq->body->iseq_encoded;
 
     // Compile a block version starting at the first instruction
-    uint8_t* native_code_ptr = ujit_compile_entry(iseq, 0);
+    uint8_t* code_ptr = gen_entry_point(iseq, 0);
 
-    if (native_code_ptr) {
-        encoded[0] = (VALUE)native_code_ptr;
+    if (code_ptr)
+    {
+        // Map the code address to the corresponding opcode
+        int first_opcode = opcode_at_pc(iseq, &encoded[0]);
+        map_addr2insn(code_ptr, first_opcode);
+        encoded[0] = (VALUE)code_ptr;
     }
 
     RB_VM_LOCK_LEAVE();
-- 
cgit v1.2.1


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

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