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

ruby-changes:68637

From: Alan <ko1@a...>
Date: Thu, 21 Oct 2021 08:11:21 +0900 (JST)
Subject: [ruby-changes:68637] 8bda11f690 (master): MicroJIT: compile after ten calls

https://git.ruby-lang.org/ruby.git/commit/?id=8bda11f690

From 8bda11f69065d08284b5990097c45a05076d36bd Mon Sep 17 00:00:00 2001
From: Alan Wu <XrXr@u...>
Date: Tue, 13 Oct 2020 11:15:22 -0400
Subject: MicroJIT: compile after ten calls

---
 compile.c      | 42 ++++++--------------------------------
 mjit.h         |  8 +++++++-
 ujit_compile.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++---------
 ujit_compile.h | 12 +++++++++--
 4 files changed, 77 insertions(+), 49 deletions(-)

diff --git a/compile.c b/compile.c
index 5f6bc8476b..aedced7c8d 100644
--- a/compile.c
+++ b/compile.c
@@ -862,46 +862,16 @@ rb_iseq_translate_threaded_code(rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/compile.c#L862
 {
 #if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
     const void * const *table = rb_vm_get_insns_address_table();
+    unsigned int i;
     VALUE *encoded = (VALUE *)iseq->body->iseq_encoded;
-    VALUE translated_insns_buf;
-
-    unsigned int insn_idx, translated_idx;
-    unsigned int next_ujit_idx = 0;
-    unsigned int translated_len = 0;
-
-    bool ujit_enabled = rb_ujit_enabled_p();
-
-    VALUE *translated_insns = ALLOCV_N(VALUE, translated_insns_buf, iseq->body->iseq_size);
-    for (insn_idx = 0; insn_idx < iseq->body->iseq_size; /* */) {
-        int insn = (int)encoded[insn_idx];
-        int len = insn_len(insn);
-        VALUE translated;
-
-        uint8_t* native_code_ptr = NULL;
 
-        // If ujit is enabled and hasn't already compiled this instruction
-        if (ujit_enabled && insn_idx >= next_ujit_idx)
-            native_code_ptr = ujit_compile_insn(iseq, insn_idx, &next_ujit_idx);
-
-        if (native_code_ptr)
-            translated = (VALUE)native_code_ptr;
-        else
-            translated = (VALUE)table[insn];
-        translated_insns[translated_len++] = translated;
-
-    	insn_idx += len;
+    for (i = 0; i < iseq->body->iseq_size; /* */ ) {
+	int insn = (int)iseq->body->iseq_encoded[i];
+	int len = insn_len(insn);
+	encoded[i] = (VALUE)table[insn];
+	i += len;
     }
-
-    insn_idx = 0;
-    for (translated_idx = 0; translated_idx < translated_len; translated_idx++) {
-        int insn = (int)encoded[insn_idx];
-        int len = insn_len(insn);
-        encoded[insn_idx] = translated_insns[translated_idx];
-        insn_idx += len;
-    }
-
     FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
-    ALLOCV_END(translated_insns_buf);
 #endif
     return COMPILE_OK;
 }
diff --git a/mjit.h b/mjit.h
index 813ac0cf21..413e6f83cc 100644
--- a/mjit.h
+++ b/mjit.h
@@ -16,6 +16,7 @@ https://github.com/ruby/ruby/blob/trunk/mjit.h#L16
 
 #include "debug_counter.h"
 #include "ruby.h"
+#include "ujit_compile.h"
 
 // Special address values of a function generated from the
 // corresponding iseq by MJIT:
@@ -142,7 +143,7 @@ mjit_exec(rb_execution_context_t *ec) https://github.com/ruby/ruby/blob/trunk/mjit.h#L143
     const rb_iseq_t *iseq;
     struct rb_iseq_constant_body *body;
 
-    if (!mjit_call_p)
+    if (!mjit_call_p && !rb_ujit_enabled_p())
         return Qundef;
     RB_DEBUG_COUNTER_INC(mjit_exec);
 
@@ -150,6 +151,11 @@ mjit_exec(rb_execution_context_t *ec) https://github.com/ruby/ruby/blob/trunk/mjit.h#L151
     body = iseq->body;
     body->total_calls++;
 
+    const int ujit_call_threashold = 10;
+    if (body->total_calls == ujit_call_threashold) {
+        rb_ujit_compile_iseq(iseq);
+    }
+
     mjit_func_t func = body->jit_func;
     if (UNLIKELY((uintptr_t)func <= LAST_JIT_ISEQ_FUNC)) {
 #  ifdef MJIT_HEADER
diff --git a/ujit_compile.c b/ujit_compile.c
index fe492da027..1f42f52d1e 100644
--- a/ujit_compile.c
+++ b/ujit_compile.c
@@ -4,6 +4,7 @@ https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L4
 #include "vm_core.h"
 #include "vm_callinfo.h"
 #include "builtin.h"
+#include "internal/compile.h"
 #include "insns_info.inc"
 #include "ujit_compile.h"
 #include "ujit_asm.h"
@@ -19,6 +20,8 @@ https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L20
 #define PLATFORM_SUPPORTED_P 1
 #endif
 
+bool rb_ujit_enabled;
+
 // Hash table of encoded instructions
 extern st_table *rb_encoded_insn_data;
 
@@ -26,11 +29,13 @@ extern st_table *rb_encoded_insn_data; https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L29
 typedef struct ctx_struct
 {
     // Current PC
-    VALUE* pc;
+    VALUE *pc;
 
     // Difference between the current stack pointer and actual stack top
     int32_t stack_diff;
 
+    const rb_iseq_t *iseq;
+
 } ctx_t;
 
 // MicroJIT code generation function signature
@@ -63,12 +68,25 @@ addr2insn_bookkeeping(void *code_ptr, int insn) https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L68
     }
 }
 
+static int
+opcode_at_pc(const rb_iseq_t *iseq, const VALUE *pc)
+{
+    const VALUE at_pc = *pc;
+    if (FL_TEST_RAW((VALUE)iseq, ISEQ_TRANSLATED)) {
+        return rb_vm_insn_addr2insn((const void *)at_pc);
+    }
+    else {
+        return (int)at_pc;
+    }
+}
+
 // Get the current instruction opcode from the context object
-int ctx_get_opcode(ctx_t* ctx)
+int ctx_get_opcode(ctx_t *ctx)
 {
-    return (int)(*ctx->pc);
+    return opcode_at_pc(ctx->iseq, ctx->pc);
 }
 
+
 // Get an instruction argument from the context object
 VALUE ctx_get_arg(ctx_t* ctx, size_t arg_idx)
 {
@@ -167,7 +185,7 @@ ujit_side_exit(codeblock_t* cb, ctx_t* ctx, VALUE* exit_pc) https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L185
     // Otherwise the interpreter may jump right back to the
     // JITted code we're trying to exit
     const void * const *table = rb_vm_get_insns_address_table();
-    int opcode = (int)(*exit_pc);
+    int opcode = opcode_at_pc(ctx->iseq, exit_pc);
     void* old_instr = (void*)table[opcode];
     mov(cb, RAX, const_ptr_opnd(exit_pc));
     mov(cb, RCX, const_ptr_opnd(old_instr));
@@ -192,11 +210,12 @@ System V ABI reference: https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L210
 https://wiki.osdev.org/System_V_ABI#x86-64
 */
 uint8_t *
-ujit_compile_insn(rb_iseq_t *iseq, unsigned int insn_idx, unsigned int* next_ujit_idx)
+ujit_compile_insn(const rb_iseq_t *iseq, unsigned int insn_idx, unsigned int* next_ujit_idx)
 {
     if (!cb) {
         return NULL;
     }
+    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,
@@ -218,19 +237,20 @@ ujit_compile_insn(rb_iseq_t *iseq, unsigned int insn_idx, unsigned int* next_uji https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L237
     //printf("write pos: %ld\n", cb->write_pos);
 
     // Get the first opcode in the sequence
-    int first_opcode = (int)iseq->body->iseq_encoded[insn_idx];
+    int first_opcode = opcode_at_pc(iseq, &encoded[insn_idx]);
 
     // Create codegen context
     ctx_t ctx;
     ctx.pc = NULL;
     ctx.stack_diff = 0;
+    ctx.iseq = iseq;
 
     // For each instruction to compile
     size_t num_instrs;
     for (num_instrs = 0;; ++num_instrs)
     {
         // Set the current PC
-        ctx.pc = &iseq->body->iseq_encoded[insn_idx];
+        ctx.pc = &encoded[insn_idx];
 
         // Get the current opcode
         int opcode = ctx_get_opcode(&ctx);
@@ -616,10 +636,33 @@ gen_opt_send_without_block(codeblock_t* cb, codeblock_t* ocb, ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L636
     */
 }
 
-bool
-rb_ujit_enabled_p(void)
+
+void
+rb_ujit_compile_iseq(const rb_iseq_t *iseq)
 {
-    return !!cb;
+#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
+    VALUE *encoded = (VALUE *)iseq->body->iseq_encoded;
+
+    unsigned int insn_idx;
+    unsigned int next_ujit_idx = 0;
+
+    for (insn_idx = 0; insn_idx < iseq->body->iseq_size; /* */) {
+        int insn = opcode_at_pc(iseq, &encoded[insn_idx]);
+        int len = insn_len(insn);
+
+        uint8_t *native_code_ptr = NULL;
+
+        // If ujit hasn't already compiled this instruction
+        if (insn_idx >= next_ujit_idx) {
+            native_code_ptr = ujit_compile_insn(iseq, insn_idx, &next_ujit_idx);
+        }
+
+        if (native_code_ptr) {
+            encoded[insn_idx] = (VALUE)native_code_ptr;
+        }
+        insn_idx += len;
+    }
+#endif
 }
 
 void
@@ -630,6 +673,7 @@ rb_ujit_init(void) https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L673
         return;
     }
 
+    rb_ujit_enabled = true;
     // Initialize the code blocks
     size_t mem_size = 128 * 1024 * 1024;
     uint8_t* mem_block = alloc_exec_mem(mem_size);
diff --git a/ujit_compile.h b/ujit_compile.h
index 624f8dc5b7..f5507ce5e4 100644
--- a/ujit_compile.h
+++ b/ujit_compile.h
@@ -10,8 +10,16 @@ typedef struct rb_iseq_struct rb_iseq_t; https://github.com/ruby/ruby/blob/trunk/ujit_compile.h#L10
 #define rb_iseq_t rb_iseq_t
 #endif
 
+extern bool rb_ujit_enabled;
+
+static inline
+bool rb_ujit_enabled_p(void)
+{
+    return rb_ujit_enabled;
+}
+
 void rb_ujit_init(void);
-bool rb_ujit_enabled_p(void);
-uint8_t* ujit_compile_insn(rb_iseq_t *iseq, unsigned int insn_idx, unsigned int* next_ujit_idx);
+uint8_t *ujit_compile_insn(const rb_iseq_t *iseq, unsigned int insn_idx, unsigned int *next_ujit_idx);
+void rb_ujit_compile_iseq(const rb_iseq_t *iseq);
 
 #endif
-- 
cgit v1.2.1


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

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