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

ruby-changes:68990

From: Maxime <ko1@a...>
Date: Thu, 21 Oct 2021 08:19:36 +0900 (JST)
Subject: [ruby-changes:68990] 0cc73ca2a9 (master): Malloc branch entries (#112)

https://git.ruby-lang.org/ruby.git/commit/?id=0cc73ca2a9

From 0cc73ca2a9a2aa5276cd022be9891475a15ecee3 Mon Sep 17 00:00:00 2001
From: Maxime Chevalier-Boisvert <maximechevalierb@g...>
Date: Mon, 19 Apr 2021 17:07:27 -0400
Subject: Malloc branch entries (#112)

* Malloc branch entries

* Add ASM comment for stack overflow check

* WIP

* Fix branch GC code. Add rb_darray_remove_unordered().

* Fix block end_pos after branch rewriting. Remove dst_patched bits.
---
 darray.h       |  10 +++
 yjit_codegen.c |   9 ++
 yjit_core.c    | 259 +++++++++++++++++++++++++++------------------------------
 yjit_core.h    |  21 +++--
 yjit_iface.c   |  29 +++++--
 5 files changed, 176 insertions(+), 152 deletions(-)

diff --git a/darray.h b/darray.h
index 71e2d7e6ce..b613d08489 100644
--- a/darray.h
+++ b/darray.h
@@ -51,10 +51,20 @@ https://github.com/ruby/ruby/blob/trunk/darray.h#L51
         1                                         \
     ) : 0)
 
+// Last element of the array
+//
+#define rb_darray_back(ary) ((ary)->data[(ary)->meta.size - 1])
+
 // Remove the last element of the array.
 //
 #define rb_darray_pop_back(ary) ((ary)->meta.size--)
 
+// Remove element at idx and replace it by the last element
+#define rb_darray_remove_unordered(ary, idx) do {   \
+    rb_darray_set(ary, idx, rb_darray_back(ary));   \
+    rb_darray_pop_back(ary);                        \
+} while (0);
+
 // Iterate over items of the array in a for loop
 //
 #define rb_darray_foreach(ary, idx_name, elem_ptr_var) \
diff --git a/yjit_codegen.c b/yjit_codegen.c
index 8d4cd02677..8cc3d5c8c8 100644
--- a/yjit_codegen.c
+++ b/yjit_codegen.c
@@ -301,6 +301,7 @@ jit_jump_to_next_insn(jitstate_t *jit, const ctx_t *current_context) https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L301
 
     // Generate the jump instruction
     gen_direct_jump(
+        jit->block,
         &reset_depth,
         jump_block
     );
@@ -722,6 +723,7 @@ jit_chain_guard(enum jcc_kinds jcc, jitstate_t *jit, const ctx_t *ctx, uint8_t d https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L723
         deeper.chain_depth++;
 
         gen_branch(
+            jit->block,
             ctx,
             (blockid_t) { jit->iseq, jit->insn_idx },
             &deeper,
@@ -1334,6 +1336,7 @@ gen_branchif(jitstate_t* jit, ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L1336
 
     // Generate the branch instructions
     gen_branch(
+        jit->block,
         ctx,
         jump_block,
         ctx,
@@ -1387,6 +1390,7 @@ gen_branchunless(jitstate_t* jit, ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L1390
 
     // Generate the branch instructions
     gen_branch(
+        jit->block,
         ctx,
         jump_block,
         ctx,
@@ -1412,6 +1416,7 @@ gen_jump(jitstate_t* jit, ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L1416
 
     // Generate the jump instruction
     gen_direct_jump(
+        jit->block,
         ctx,
         jump_block
     );
@@ -1726,6 +1731,7 @@ gen_oswb_iseq(jitstate_t *jit, ctx_t *ctx, const struct rb_callinfo *ci, const r https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L1731
 
     // Stack overflow check
     // #define CHECK_VM_STACK_OVERFLOW0(cfp, sp, margin)
+    ADD_COMMENT(cb, "stack overflow check");
     lea(cb, REG0, ctx_sp_opnd(ctx, sizeof(VALUE) * (num_locals + iseq->body->stack_max) + sizeof(rb_control_frame_t)));
     cmp(cb, REG_CFP, REG0);
     jle_ptr(cb, COUNTED_EXIT(side_exit, oswb_se_cf_overflow));
@@ -1802,6 +1808,7 @@ gen_oswb_iseq(jitstate_t *jit, ctx_t *ctx, const struct rb_callinfo *ci, const r https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L1808
 
     // Write the JIT return address on the callee frame
     gen_branch(
+        jit->block,
         ctx,
         return_block,
         &return_ctx,
@@ -1818,6 +1825,7 @@ gen_oswb_iseq(jitstate_t *jit, ctx_t *ctx, const struct rb_callinfo *ci, const r https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L1825
 
     // Directly jump to the entry point of the callee
     gen_direct_jump(
+        jit->block,
         &callee_ctx,
         (blockid_t){ iseq, 0 }
     );
@@ -2049,6 +2057,7 @@ gen_opt_getinlinecache(jitstate_t *jit, ctx_t *ctx) https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L2057
     // Jump over the code for filling the cache
     uint32_t jump_idx = jit_next_insn_idx(jit) + (int32_t)jump_offset;
     gen_direct_jump(
+        jit->block,
         ctx,
         (blockid_t){ .iseq = jit->iseq, .idx = jump_idx }
     );
diff --git a/yjit_core.c b/yjit_core.c
index 2584714f7a..56450840cd 100644
--- a/yjit_core.c
+++ b/yjit_core.c
@@ -12,13 +12,6 @@ https://github.com/ruby/ruby/blob/trunk/yjit_core.c#L12
 // Maximum number of versions per block
 #define MAX_VERSIONS 4
 
-// Maximum number of branch instructions we can track
-#define MAX_BRANCHES 250000
-
-// Registered branch entries
-branch_t branch_entries[MAX_BRANCHES];
-uint32_t num_branches = 0;
-
 /*
 Get an operand for the adjusted stack pointer address
 */
@@ -385,6 +378,26 @@ add_block_version(blockid_t blockid, block_t* block) https://github.com/ruby/ruby/blob/trunk/yjit_core.c#L378
     }
 }
 
+// Create a new outgoing branch entry for a block
+static branch_t*
+make_branch_entry(block_t* block, const ctx_t* src_ctx, branchgen_fn gen_fn)
+{
+    RUBY_ASSERT(block != NULL);
+
+    // Allocate and zero-initialize
+    branch_t* branch = calloc(1, sizeof(branch_t));
+
+    branch->block = block;
+    branch->src_ctx = *src_ctx;
+    branch->gen_fn = gen_fn;
+    branch->shape = SHAPE_DEFAULT;
+
+    // Add to the list of outgoing branches for the block
+    rb_darray_append(&block->outgoing, branch);
+
+    return branch;
+}
+
 // Retrieve a basic block version for an (iseq, idx) tuple
 block_t* find_block_version(blockid_t blockid, const ctx_t* ctx)
 {
@@ -410,15 +423,6 @@ block_t* find_block_version(blockid_t blockid, const ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/yjit_core.c#L423
     return best_version;
 }
 
-void
-yjit_branches_update_references(void)
-{
-    for (uint32_t i = 0; i < num_branches; i++) {
-        branch_entries[i].targets[0].iseq = (const void *)rb_gc_location((VALUE)branch_entries[i].targets[0].iseq);
-        branch_entries[i].targets[1].iseq = (const void *)rb_gc_location((VALUE)branch_entries[i].targets[1].iseq);
-    }
-}
-
 // Compile a new block version immediately
 block_t* gen_block_version(blockid_t blockid, const ctx_t* start_ctx, rb_execution_context_t* ec)
 {
@@ -442,14 +446,13 @@ block_t* gen_block_version(blockid_t blockid, const ctx_t* start_ctx, rb_executi https://github.com/ruby/ruby/blob/trunk/yjit_core.c#L446
 
     // For each successor block to compile
     for (;;) {
-        // If no branches were generated, stop
-        if (num_branches == 0) {
+        // If the previous block compiled doesn't have outgoing branches, stop
+        if (rb_darray_size(block->outgoing) == 0) {
             break;
         }
 
-        // Get the last branch entry
-        uint32_t branch_idx = num_branches - 1;
-        branch_t* last_branch = &branch_entries[num_branches - 1];
+        // Get the last outgoing branch from the previous block
+        branch_t* last_branch = rb_darray_back(block->outgoing);
 
         // If there is no next block to compile, stop
         if (last_branch->dst_addrs[0] || last_branch->dst_addrs[1]) {
@@ -476,7 +479,8 @@ block_t* gen_block_version(blockid_t blockid, const ctx_t* start_ctx, rb_executi https://github.com/ruby/ruby/blob/trunk/yjit_core.c#L479
 
         // Patch the last branch address
         last_branch->dst_addrs[0] = cb_get_ptr(cb, block->start_pos);
-        rb_darray_append(&block->incoming, branch_idx);
+        rb_darray_append(&block->incoming, last_branch);
+        last_branch->blocks[0] = block;
 
         RUBY_ASSERT(block->start_pos == last_branch->end_pos);
     }
@@ -508,7 +512,7 @@ uint8_t* gen_entry_point(const rb_iseq_t *iseq, uint32_t insn_idx, rb_execution_ https://github.com/ruby/ruby/blob/trunk/yjit_core.c#L512
 // Called by the generated code when a branch stub is executed
 // Triggers compilation of branches and code patching
 static uint8_t *
-branch_stub_hit(const uint32_t branch_idx, const uint32_t target_idx, rb_execution_context_t* ec)
+branch_stub_hit(branch_t* branch, const uint32_t target_idx, rb_execution_context_t* ec)
 {
     uint8_t* dst_addr;
     ctx_t generic_ctx;
@@ -518,20 +522,19 @@ branch_stub_hit(const uint32_t branch_idx, const uint32_t target_idx, rb_executi https://github.com/ruby/ruby/blob/trunk/yjit_core.c#L522
     RB_VM_LOCK_ENTER();
     rb_vm_barrier();
 
-    RUBY_ASSERT(branch_idx < num_branches);
+    RUBY_ASSERT(branch != NULL);
     RUBY_ASSERT(target_idx < 2);
-    branch_t *branch = &branch_entries[branch_idx];
     blockid_t target = branch->targets[target_idx];
     const ctx_t* target_ctx = &branch->target_ctxs[target_idx];
 
     // If this branch has already been patched, return the dst address
     // Note: ractors can cause the same stub to be hit multiple times
-    if (branch->dst_patched & (1 << target_idx)) {
-        dst_addr =  branch->dst_addrs[target_idx];
+    if (branch->blocks[target_idx]) {
+        dst_addr = branch->dst_addrs[target_idx];
     }
     else
     {
-        //fprintf(stderr, "\nstub hit, branch idx: %d, target idx: %d\n", branch_idx, target_idx);
+        //fprintf(stderr, "\nstub hit, branch: %p, target idx: %d\n", branch, 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);
 
@@ -566,6 +569,9 @@ branch_stub_hit(const uint32_t branch_idx, const uint32_t target_idx, rb_executi https://github.com/ruby/ruby/blob/trunk/yjit_core.c#L569
 
             // If the new block can be generated right after the branch (at cb->write_pos)
             if (cb->write_pos == branch->end_pos) {
+                // This branch should be terminating its block
+                RUBY_ (... truncated)

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

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