ruby-changes:68702
From: Maxime <ko1@a...>
Date: Thu, 21 Oct 2021 08:12:29 +0900 (JST)
Subject: [ruby-changes:68702] 4a57107696 (master): Sketch code to invalidate basic blocks. Rename version_t to block_t.
https://git.ruby-lang.org/ruby.git/commit/?id=4a57107696 From 4a5710769609c35a32a071cc4cd3bcebdc3ec908 Mon Sep 17 00:00:00 2001 From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...> Date: Thu, 14 Jan 2021 13:33:19 -0500 Subject: Sketch code to invalidate basic blocks. Rename version_t to block_t. --- ujit_codegen.c | 22 +++---- ujit_codegen.h | 6 +- ujit_core.c | 180 ++++++++++++++++++++++++++++++++++++++------------------- ujit_core.h | 11 ++-- 4 files changed, 142 insertions(+), 77 deletions(-) diff --git a/ujit_codegen.c b/ujit_codegen.c index 722f799e64..17a9447812 100644 --- a/ujit_codegen.c +++ b/ujit_codegen.c @@ -102,7 +102,7 @@ Compile an interpreter entry block to be inserted into an iseq https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L102 Returns `NULL` if compilation fails. */ uint8_t* -ujit_gen_entry(version_t* version) +ujit_gen_entry(block_t* block) { assert (cb != NULL); @@ -122,7 +122,7 @@ ujit_gen_entry(version_t* version) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L122 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_gen_code(version); + uint32_t num_instrs = ujit_gen_code(block); // If no instructions were compiled if (num_instrs == 0) { @@ -133,19 +133,19 @@ ujit_gen_entry(version_t* version) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L133 } /* -Compile a sequence of bytecode instructions +Compile a sequence of bytecode instructions for a given basic block version */ uint32_t -ujit_gen_code(version_t* version) +ujit_gen_code(block_t* block) { assert (cb != NULL); - // Copy the version's context to avoid mutating it - ctx_t ctx_copy = version->ctx; + // Copy the block's context to avoid mutating it + ctx_t ctx_copy = block->ctx; ctx_t* ctx = &ctx_copy; - const rb_iseq_t *iseq = version->blockid.iseq; - uint32_t insn_idx = version->blockid.idx; + 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 @@ -163,7 +163,7 @@ ujit_gen_code(version_t* version) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L163 // Initialize JIT state object jitstate_t jit = { - version, + block, iseq }; @@ -216,7 +216,7 @@ ujit_gen_code(version_t* version) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L216 if (UJIT_DUMP_MODE >= 2) { // Dump list of compiled instrutions fprintf(stderr, "Compiled the following for iseq=%p:\n", (void *)iseq); - VALUE *pc = &encoded[version->blockid.idx]; + VALUE *pc = &encoded[block->blockid.idx]; VALUE *end_pc = &encoded[insn_idx]; while (pc < end_pc) { int opcode = opcode_at_pc(iseq, pc); @@ -961,6 +961,7 @@ gen_branchunless(jitstate_t* jit, ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L961 // Generate the branch instructions gen_branch( + jit->block, ctx, jump_block, ctx, @@ -1004,6 +1005,7 @@ gen_jump(jitstate_t* jit, ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L1005 // Generate the jump instruction gen_branch( + jit->block, ctx, jump_block, ctx, diff --git a/ujit_codegen.h b/ujit_codegen.h index 0564c594d3..192cf29d61 100644 --- a/ujit_codegen.h +++ b/ujit_codegen.h @@ -12,7 +12,7 @@ codeblock_t* ocb; https://github.com/ruby/ruby/blob/trunk/ujit_codegen.h#L12 typedef struct JITState { // Block version being compiled - version_t* version; + block_t* block; // Instruction sequence this is associated with const rb_iseq_t *iseq; @@ -40,9 +40,9 @@ typedef struct OpDesc https://github.com/ruby/ruby/blob/trunk/ujit_codegen.h#L40 } opdesc_t; -uint8_t* ujit_gen_entry(version_t* version); +uint8_t* ujit_gen_entry(block_t* block); -uint32_t ujit_gen_code(version_t* version); +uint32_t ujit_gen_code(block_t* block); void ujit_init_codegen(void); diff --git a/ujit_core.c b/ujit_core.c index 2cb1c252de..77c329970b 100644 --- a/ujit_core.c +++ b/ujit_core.c @@ -70,12 +70,12 @@ ctx_stack_opnd(ctx_t* ctx, int32_t idx) https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L70 } // Retrieve a basic block version for an (iseq, idx) tuple -version_t* find_block_version(blockid_t block, const ctx_t* ctx) +block_t* find_block_version(blockid_t blockid, const ctx_t* ctx) { // If there exists a version for this block id st_data_t st_version; - if (rb_st_lookup(version_tbl, (st_data_t)&block, &st_version)) { - return (version_t*)st_version; + if (rb_st_lookup(version_tbl, (st_data_t)&blockid, &st_version)) { + return (block_t*)st_version; } // @@ -85,68 +85,79 @@ version_t* find_block_version(blockid_t block, const ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L85 return NULL; } // Compile a new block version immediately -version_t* gen_block_version(blockid_t blockid, const ctx_t* ctx) +block_t* gen_block_version(blockid_t blockid, const ctx_t* ctx) { // Allocate a version object - version_t* p_version = malloc(sizeof(version_t)); - memcpy(&p_version->blockid, &blockid, sizeof(blockid_t)); - memcpy(&p_version->ctx, ctx, sizeof(ctx_t)); - p_version->incoming = NULL; - p_version->num_incoming = 0; + block_t* p_block = malloc(sizeof(block_t)); + memcpy(&p_block->blockid, &blockid, sizeof(blockid_t)); + memcpy(&p_block->ctx, ctx, sizeof(ctx_t)); + p_block->incoming = NULL; + p_block->num_incoming = 0; + p_block->end_pos = 0; + + // The block starts at the current position + p_block->start_pos = cb->write_pos; // Compile the block version - p_version->start_pos = cb->write_pos; - ujit_gen_code(p_version); - p_version->end_pos = cb->write_pos; + ujit_gen_code(p_block); + + // The block may have been terminated in gen_branch + if (p_block->end_pos == 0) + p_block->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); + st_insert(version_tbl, (st_data_t)&p_block->blockid, (st_data_t)p_block); - return p_version; + return p_block; } // 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)); + block_t* p_block = malloc(sizeof(block_t)); blockid_t blockid = { iseq, insn_idx }; - memcpy(&p_version->blockid, &blockid, sizeof(blockid_t)); - p_version->incoming = NULL; - p_version->num_incoming = 0; + memcpy(&p_block->blockid, &blockid, sizeof(blockid_t)); + p_block->incoming = NULL; + p_block->num_incoming = 0; + p_block->end_pos = 0; // The entry context makes no assumptions about types ctx_t ctx = { 0 }; - memcpy(&p_version->ctx, &ctx, sizeof(ctx_t)); + memcpy(&p_block->ctx, &ctx, sizeof(ctx_t)); + + // The block starts at the current position + p_block->start_pos = cb->write_pos; // 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; + uint8_t* code_ptr = ujit_gen_entry(p_block); + + // The block may have been terminated in gen_branch + if (p_block->end_pos == 0) + p_block->end_pos = cb->write_pos; // If we couldn't generate any code if (!code_ptr) { - free(p_version); + free(p_block); return NULL; } // Keep track of the new block version - st_insert(version_tbl, (st_data_t)&p_version->blockid, (st_data_t)p_version); + st_insert(version_tbl, (st_data_t)&p_block->blockid, (st_data_t)p_block); return code_ptr; } // Add an incoming branch for a given block version -static void add_incoming(version_t* p_version, uint32_t branch_idx) +static void add_incoming(block_t* p_block, uint32_t branch_idx) { // Add this branch to the list of incoming branches for the target - uint32_t* new_list = malloc(sizeof(uint32_t) * p_version->num_incoming + 1); - memcpy(new_list, p_version->incoming, p_version->num_incoming); - new_list[p_version->num_incoming] = branch_idx; - p_version->incoming = new_list; - p_version->num_incoming += 1; - //fprintf(stderr, "num_incoming: %d\n", p_version->num_incoming); + uint32_t* new_list = malloc(sizeof(uint32_t) * p_block->num_incoming + 1); + memcpy(new_list, p_block->incoming, p_block->num_incoming); + new_list[p_block->num_incoming] = branch_idx; + p_block->incoming = new_list; + p_block->num_incoming += 1; } // Called by the generated code when a branch stub is executed @@ -176,19 +187,19 @@ uint8_t* branch_stub_hit(uint32_t branch_idx, uint32_t target_idx) https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L187 } // Try to find a compiled version of this block - version_t* p_version = find_block_version(target, target_ctx); + block_t* p_block = find_block_version(target, target_ctx); // If this block hasn't yet been compiled - if (!p_version) + if (!p_block) { - p_version = gen_block_version(target, target_ctx); + p_block = gen_block_version(target, target_ctx); } // Add this branch to the list of incoming branches for the target - add_incoming(p_version, branch_idx); + add_incoming(p_block, branch_idx); // Update the branch target address - uint8_t* dst_addr = cb_get_ptr(cb, p_version->start_pos); + uint8_t* dst_addr = cb_get_ptr(cb, p_block->start_pos); branch->dst_addrs[target_idx] = dst_addr; // Rewrite the branch with the new jump target address @@ -198,6 +209 (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/