ruby-changes:68904
From: Maxime <ko1@a...>
Date: Thu, 21 Oct 2021 08:13:05 +0900 (JST)
Subject: [ruby-changes:68904] 09479c33f5 (master): Implement block version limit
https://git.ruby-lang.org/ruby.git/commit/?id=09479c33f5 From 09479c33f54423910674780d1fcb7834e98ef561 Mon Sep 17 00:00:00 2001 From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...> Date: Wed, 27 Jan 2021 13:02:55 -0500 Subject: Implement block version limit --- ujit_core.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- ujit_core.h | 3 --- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/ujit_core.c b/ujit_core.c index 8d6680fc85..1aa6824fad 100644 --- a/ujit_core.c +++ b/ujit_core.c @@ -10,9 +10,15 @@ https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L10 #include "ujit_core.h" #include "ujit_codegen.h" +// Maximum number of versions per block +#define MAX_VERSIONS 4 + // Maximum number of branch instructions we can track #define MAX_BRANCHES 32768 +// Default versioning context (no type information) +const ctx_t DEFAULT_CTX = { { 0 }, 0 }; + // Table of block versions indexed by (iseq, index) tuples st_table * version_tbl; @@ -168,6 +174,25 @@ static void add_incoming(block_t* p_block, uint32_t branch_idx) https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L174 p_block->num_incoming += 1; } +// Count the number of block versions matching a given blockid +static size_t count_block_versions(blockid_t blockid) +{ + // If there exists a version for this block id + block_t* first_version; + if (!rb_st_lookup(version_tbl, (st_data_t)&blockid, (st_data_t*)&first_version)) + return 0; + + size_t count = 0; + + // For each version matching the blockid + for (block_t* version = first_version; version != NULL; version = version->next) + { + count += 1; + } + + return count; +} + // Retrieve a basic block version for an (iseq, idx) tuple block_t* find_block_version(blockid_t blockid, const ctx_t* ctx) { @@ -199,6 +224,7 @@ block_t* find_block_version(blockid_t blockid, const ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L224 return best_version; } + // Compile a new block version immediately block_t* gen_block_version(blockid_t blockid, const ctx_t* start_ctx) { @@ -265,13 +291,12 @@ uint8_t* gen_entry_point(const rb_iseq_t *iseq, uint32_t insn_idx) https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L291 { // The entry context makes no assumptions about types blockid_t blockid = { iseq, insn_idx }; - ctx_t ctx = { { 0 }, 0 }; // Write the interpreter entry prologue uint8_t* code_ptr = ujit_entry_prologue(); // Try to generate code for the entry block - block_t* block = gen_block_version(blockid, &ctx); + block_t* block = gen_block_version(blockid, &DEFAULT_CTX); // If we couldn't generate any code if (block->end_idx == insn_idx) @@ -294,7 +319,7 @@ uint8_t* branch_stub_hit(uint32_t branch_idx, uint32_t target_idx) https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L319 RUBY_ASSERT(target_idx < 2); branch_t *branch = &branch_entries[branch_idx]; blockid_t target = branch->targets[target_idx]; - ctx_t* target_ctx = &branch->target_ctxs[target_idx]; + const ctx_t* target_ctx = &branch->target_ctxs[target_idx]; //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); @@ -311,6 +336,15 @@ uint8_t* branch_stub_hit(uint32_t branch_idx, uint32_t target_idx) https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L336 RUBY_ASSERT(cb->write_pos <= branch->end_pos); } + // Limit the number of block versions + ctx_t generic_ctx = DEFAULT_CTX; + generic_ctx.stack_size = target_ctx->stack_size; + if (count_block_versions(target) >= MAX_VERSIONS - 1) + { + fprintf(stderr, "version limit hit in branch_stub_hit\n"); + target_ctx = &generic_ctx; + } + // Try to find a compiled version of this block block_t* p_block = find_block_version(target, target_ctx); @@ -465,6 +499,15 @@ void gen_direct_jump( https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L499 uint32_t start_pos; uint32_t end_pos; + // Limit the number of block versions + ctx_t generic_ctx = DEFAULT_CTX; + generic_ctx.stack_size = ctx->stack_size; + if (count_block_versions(target0) >= MAX_VERSIONS - 1) + { + fprintf(stderr, "version limit hit in branch_stub_hit\n"); + ctx = &generic_ctx; + } + block_t* p_block = find_block_version(target0, ctx); // If the version already exists diff --git a/ujit_core.h b/ujit_core.h index c86a9412dc..27f33c5e9b 100644 --- a/ujit_core.h +++ b/ujit_core.h @@ -17,9 +17,6 @@ https://github.com/ruby/ruby/blob/trunk/ujit_core.h#L17 #define REG0_32 EAX #define REG1_32 ECX -// Maximum number of versions per block -#define MAX_VERSIONS 5 - // Maximum number of temp value types we keep track of #define MAX_TEMP_TYPES 8 -- cgit v1.2.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/