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

ruby-changes:68831

From: Maxime <ko1@a...>
Date: Thu, 21 Oct 2021 08:14:09 +0900 (JST)
Subject: [ruby-changes:68831] 7f4000b1f4 (master): Machinery to implement deferred compilation

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

From 7f4000b1f430c22fd35c50201271d0abd4fff358 Mon Sep 17 00:00:00 2001
From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...>
Date: Fri, 5 Mar 2021 15:45:44 -0500
Subject: Machinery to implement deferred compilation

---
 bootstraptest/test_yjit.rb | 22 +++++++++++++++++++
 ujit_codegen.c             | 47 +++++++++++++++++-----------------------
 ujit_core.c                | 54 ++++++++++++++++++++++++++++++----------------
 ujit_core.h                | 18 +++++++++++++---
 version.c                  |  2 +-
 5 files changed, 94 insertions(+), 49 deletions(-)

diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb
index 0f67c6ebbb..cf79ccd101 100644
--- a/bootstraptest/test_yjit.rb
+++ b/bootstraptest/test_yjit.rb
@@ -190,6 +190,28 @@ assert_normal_exit %q{ https://github.com/ruby/ruby/blob/trunk/bootstraptest/test_yjit.rb#L190
   end
 }
 
+# Test getinstancevariable and inline caches
+assert_equal '6', %q{
+  class Foo
+    def initialize
+      @x1 = 1
+      @x2 = 1
+      @x2 = 1
+      @x3 = 1
+      @x4 = 3
+    end
+
+    def bar
+      x = 1
+      @x4 + @x4
+    end
+  end
+
+  f = Foo.new
+  f.bar
+  f.bar
+}
+
 # Test that getinstancevariable codegen checks for extended table size
 assert_equal "nil\n", %q{
   class A
diff --git a/ujit_codegen.c b/ujit_codegen.c
index 0b2c52a844..86e1242f21 100644
--- a/ujit_codegen.c
+++ b/ujit_codegen.c
@@ -82,17 +82,17 @@ 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#L82
 // Check if we are compiling the instruction at the stub PC
 // Meaning we are compiling the instruction that is next to execute
 static bool
-jit_at_current_insn(jitstate_t* jit, ctx_t* ctx)
+jit_at_current_insn(jitstate_t* jit)
 {
-    const VALUE* stub_pc = jit->ec->cfp->pc;
-    return (stub_pc == jit->pc);
+    const VALUE* ec_pc = jit->ec->cfp->pc;
+    return (ec_pc == jit->pc);
 }
 
 // Peek at the topmost value on the Ruby stack
 static VALUE
 jit_peek_at_stack(jitstate_t* jit, ctx_t* ctx)
 {
-    RUBY_ASSERT(jit_at_current_insn(jit, ctx));
+    RUBY_ASSERT(jit_at_current_insn(jit));
 
     VALUE* sp = jit->ec->cfp->sp + ctx->sp_offset;
 
@@ -317,7 +317,13 @@ ujit_gen_block(ctx_t* ctx, block_t* block, rb_execution_context_t* ec) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L317
         // Call the code generation function
         bool continue_generating = p_desc->gen_fn(&jit, ctx);
 
-        if (!continue_generating) {
+        // For now, reset the chain depth after each instruction
+        ctx->chain_depth = 0;
+
+        // 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, jit.pc);
             break;
         }
 
@@ -572,32 +578,20 @@ gen_getinstancevariable(jitstate_t* jit, ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L578
         return UJIT_CANT_COMPILE;
     }
 
+    // Defer compilation so we can peek at the topmost object
+    if (!jit_at_current_insn(jit))
+    {
+        defer_compilation(jit->block, jit->insn_idx, ctx);
+        return UJIT_END_BLOCK;
+    }
 
+    // Peek at the topmost value on the stack at compilation time
+    VALUE top_val = jit_peek_at_stack(jit, ctx);
 
-
-
-    /*
-    num_versions = count_block_versions(this_instruction);
-
-    if (num_versions > N)
-        return JIT_CANT_COMPILE;
-
-    
-    if (defer_compilation(this_instruction, ctx))
-        return JIT_END_BLOCK;
-
-
-    VALUE top_val = jit_peek_at_stack();
-    
-
-
-
-    class = get_ruby_class(top_val);
+    // TODO: play with deferred compilation and sidechains! :)
 
 
 
-    guard_object_class(class, current_instr);
-    */
 
 
 
@@ -1452,7 +1446,6 @@ gen_oswb_iseq(jitstate_t* jit, ctx_t* ctx, struct rb_call_data * cd, const rb_ca https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L1446
     cmp(cb, klass_opnd, REG1);
     jne_ptr(cb, COUNTED_EXIT(side_exit, oswb_se_cc_klass_differ));
 
-
     if (METHOD_ENTRY_VISI(cme) == METHOD_VISI_PROTECTED) {
         // Generate ancestry guard for protected callee.
         jit_protected_guard(jit, cb, cme, side_exit);
diff --git a/ujit_core.c b/ujit_core.c
index f2215cc9bf..c1d2bfb650 100644
--- a/ujit_core.c
+++ b/ujit_core.c
@@ -113,6 +113,15 @@ Returns INT_MAX if incompatible https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L113
 */
 int ctx_diff(const ctx_t* src, const ctx_t* dst)
 {
+    // Can only lookup the first version in the chain
+    if (dst->chain_depth != 0)
+        return INT_MAX;
+
+    // Blocks with depth > 0 always produce new versions
+    // Sidechains cannot overlap
+    if (src->chain_depth != 0)
+        return INT_MAX;
+
     if (dst->stack_size != src->stack_size)
         return INT_MAX;
 
@@ -353,6 +362,7 @@ 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#L362
 
     //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);
+    //fprintf(stderr, "chain_depth=%d\n", target_ctx->chain_depth);
 
     // Update the PC in the current CFP, because it
     // may be out of sync in JITted code
@@ -376,7 +386,7 @@ 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#L386
     generic_ctx.sp_offset = target_ctx->sp_offset;
     if (get_num_versions(target) >= MAX_VERSIONS - 1)
     {
-        fprintf(stderr, "version limit hit in branch_stub_hit\n");
+        //fprintf(stderr, "version limit hit in branch_stub_hit\n");
         target_ctx = &generic_ctx;
     }
 
@@ -542,7 +552,7 @@ void gen_direct_jump( https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L552
     generic_ctx.sp_offset = ctx->sp_offset;
     if (get_num_versions(target0) >= MAX_VERSIONS - 1)
     {
-        fprintf(stderr, "version limit hit in gen_direct_jump\n");
+        //fprintf(stderr, "version limit hit in gen_direct_jump\n");
         ctx = &generic_ctx;
     }
 
@@ -588,42 +598,50 @@ void gen_direct_jump( https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L598
 // Create a stub to force the code up to this point to be executed
 void defer_compilation(
     block_t* block,
-    ctx_t* cur_ctx,
-    uint32_t insn_idx
+    uint32_t insn_idx,
+    ctx_t* cur_ctx
 )
 {
+    //fprintf(stderr, "defer compilation at (%p, %d) depth=%d\n", block->blockid.iseq, insn_idx, cur_ctx->chain_depth);
 
+    if (cur_ctx->chain_depth != 0) {
+        rb_backtrace();
+        exit(1);
+    }
 
+    ctx_t next_ctx = *cur_ctx;
 
+    if (next_ctx.chain_depth >= UINT8_MAX) {
+        rb_bug("max block version chain depth reached");
+    }
 
+    next_ctx.chain_depth += 1;
 
-
-
-
-
-
-
-
-    /*
     RUBY_ASSERT(num_branches < MAX_BRANCHES);
     uint32_t branch_idx = num_branches++;
 
+    // Get the branch targets or stubs
+    blockid_t target0 = (blockid_t){ block->blockid.iseq, insn_idx };
+    uint8_t* dst_addr0 = get_branch_target(target0, &next_ctx, branch_idx, 0);
+
+    // Call the branch generation function
+    uint32_t start_pos = cb->write_pos;
+    gen_jump_branch(cb, dst_addr0, NULL, SHAPE_DEFAULT);
+    uint32_t end_pos = cb->write_pos;
+
     // Register this branch entry
     branch_t branch_entry = {
         start_pos,
         end_pos,
-        *ctx,
+        *cur_ctx,
         { target0, BLOCKID_NULL },
-        { *ctx, *ctx },
+        { next_ctx, next_ctx },
         { dst_addr0, NULL },
         gen_jump_branch,
-        branch_shape
+        SHAPE_DEFAULT
     };
 
     branch_entries[branch_idx] = branch_entry;
-    */
-
-
 }
 
 // Remove all references to a block then free it.
diff --git a/ujit_core.h b/ujit_core.h
index 92d2dd594f..cf82dfe5af 100644
--- a/ujit_core.h
+++ b/ujit_core.h
@@ -20,12 +20,18 @@ https://github.com/ruby/ruby/blob/trunk/ujit_core.h#L20
 // Maximum number of temp value types we keep track of
 #define MAX_TEMP_TYPES 8
 
+// Default versioning context (no type information)
+#define DEFAULT_CTX ( (ctx_t){ 0 } )
+
 /**
 Code generation context
 Contains information we can use to optimize code
 */
 typedef struct CtxStruct
 {
+    // Depth of this block in the sidechain (eg: inline-cache chain)
+    int8_t chain_depth;
+
     // Temporary variable types we keep track of
     // Values are `ruby_value_type`
     // T_NONE==0 is the unknown type
@@ -58,12 +64,12 @@ typedef struct BlockId https://github.com/ruby/ruby/blob/trunk/ujit_core.h#L64
 static const blockid_t BLOCKID_NULL = { 0, 0 };
 
 /// Branch code shape enumeration
-enum uint8_t
+typedef enum : int8_t
 {
     SHAPE_NEXT0,  // Target 0 is next
     SHAPE_NEXT1,  // Target 1 is next
     SHAPE_DEFAULT // Neither target is next
-};
+} branch_shape_t;
 
 // Branch code generation function signature
 typedef void (*branchgen_fn)(codeblock_t* cb, uint8_t* target0, uint8_t* target1, uint8_t shape);
@@ -92,7 +98,7 @@ typedef struct BranchEntry https://github.com/ruby/ruby/blob/trunk/ujit_core.h#L98
     branchgen_fn gen_fn;
 
     // Shape of the branch
-    uint8_t shape;
+    branch_shape_t shape;
 
 } branch_t;
 
@@ -159,6 +165,12 @@ void gen_direct_jump( https://github.com/ruby/ruby/blob/trunk/ujit_core.h#L165
     blockid_t target0
 );
 
+void defer_compilation(
+    block_t* block,
+    uint32_t insn_idx,
+    ctx_t* cur_ctx
+);
+
 void invalidate_block_version(block_t* block);
 
 void ujit_init_core(void);
diff --git a/version.c b/version.c
index 9c1aaff32d..7a5a2cb229 100644
--- a/version.c
+++ b/version.c
@@ -126,7 +126,7 @@ ruby_show_version(void) https://github.com/ruby/ruby/blob/trunk/version.c#L126
     }
 
     if (rb_ujit_enabled_p()) {
-        fputs("uJIT is enabled\n", stdout);
+        fputs("YJIT is enabled\n", stdout);
     }
 #ifdef RUBY_LAST_COMMIT_TITLE
     fputs("last_commit=" RUBY_L (... truncated)

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

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