ruby-changes:72300
From: Aaron <ko1@a...>
Date: Fri, 24 Jun 2022 08:52:16 +0900 (JST)
Subject: [ruby-changes:72300] 8d63a04703 (master): Flatten bitmap when there is only one element
https://git.ruby-lang.org/ruby.git/commit/?id=8d63a04703 From 8d63a0470392f3b5810941bdf36f23d2122df16a Mon Sep 17 00:00:00 2001 From: Aaron Patterson <tenderlove@r...> Date: Thu, 23 Jun 2022 15:46:53 -0700 Subject: Flatten bitmap when there is only one element We can avoid allocating a bitmap when the number of elements in the iseq is fewer than the size of an iseq_bits_t --- compile.c | 43 ++++++++++++++++++++++++++++++++++++++----- iseq.c | 47 +++++++++++++++++++++++++++++------------------ vm_core.h | 5 ++++- 3 files changed, 71 insertions(+), 24 deletions(-) diff --git a/compile.c b/compile.c index 2b007f92fd..8ebe6f33ad 100644 --- a/compile.c +++ b/compile.c @@ -2336,7 +2336,17 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) https://github.com/ruby/ruby/blob/trunk/compile.c#L2336 // of the number of bits in an unsigned long. // Allocate enough room for the bitmask list - iseq_bits_t * mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index)); + iseq_bits_t * mark_offset_bits; + int code_size = code_index; + + iseq_bits_t tmp[1] = {0}; + + if (ISEQ_MBITS_BUFLEN(code_index) == 1) { + mark_offset_bits = tmp; + } + else { + mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index)); + } list = FIRST_ELEMENT(anchor); insns_info_index = code_index = sp = 0; @@ -2505,7 +2515,9 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) https://github.com/ruby/ruby/blob/trunk/compile.c#L2515 xfree(generated_iseq); xfree(insns_info); xfree(positions); - xfree(mark_offset_bits); + if (ISEQ_MBITS_BUFLEN(code_size) > 1) { + xfree(mark_offset_bits); + } debug_list(anchor, list); COMPILE_ERROR(iseq, adjust->line_no, "iseq_set_sequence: adjust bug to %d %d < %d", @@ -2525,7 +2537,13 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) https://github.com/ruby/ruby/blob/trunk/compile.c#L2537 body->iseq_encoded = (void *)generated_iseq; body->iseq_size = code_index; body->stack_max = stack_max; - body->mark_offset_bits = mark_offset_bits; + + if (ISEQ_MBITS_BUFLEN(body->iseq_size) == 1) { + body->mark_bits.single = mark_offset_bits[0]; + } + else { + body->mark_bits.list = mark_offset_bits; + } /* get rid of memory leak when REALLOC failed */ body->insns_info.body = insns_info; @@ -11189,8 +11207,16 @@ ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecod https://github.com/ruby/ruby/blob/trunk/compile.c#L11207 struct rb_call_data *cd_entries = load_body->call_data; union iseq_inline_storage_entry *is_entries = load_body->is_entries; - iseq_bits_t * mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size)); - load_body->mark_offset_bits = mark_offset_bits; + iseq_bits_t * mark_offset_bits; + + iseq_bits_t tmp[1] = {0}; + + if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) { + mark_offset_bits = tmp; + } + else { + mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size)); + } unsigned int min_ic_index, min_ise_index, min_ivc_index; min_ic_index = min_ise_index = min_ivc_index = UINT_MAX; @@ -11329,6 +11355,13 @@ ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecod https://github.com/ruby/ruby/blob/trunk/compile.c#L11355 load_body->iseq_encoded = code; load_body->iseq_size = code_index; + if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) { + load_body->mark_bits.single = mark_offset_bits[0]; + } + else { + load_body->mark_bits.list = mark_offset_bits; + } + assert(code_index == iseq_size); assert(reading_pos == bytecode_offset + bytecode_size); return code; diff --git a/iseq.c b/iseq.c index 1b9599aeda..b87939037b 100644 --- a/iseq.c +++ b/iseq.c @@ -193,7 +193,9 @@ rb_iseq_free(const rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/iseq.c#L193 } ruby_xfree((void *)body->catch_table); ruby_xfree((void *)body->param.opt_table); - ruby_xfree((void *)body->mark_offset_bits); + if (ISEQ_MBITS_BUFLEN(body->iseq_size) > 1) { + ruby_xfree((void *)body->mark_bits.list); + } if (body->param.keyword != NULL) { ruby_xfree((void *)body->param.keyword->default_values); @@ -313,6 +315,25 @@ iseq_extract_values(VALUE *code, size_t pos, iseq_value_itr_t * func, void *data https://github.com/ruby/ruby/blob/trunk/iseq.c#L315 return len; } +static inline void +iseq_scan_bits(unsigned int i, iseq_bits_t bits, VALUE *code, iseq_value_itr_t *func, void *data) +{ + unsigned int count = 0; + + while(bits) { + if (bits & 0x1) { + unsigned int index = (i * ISEQ_MBITS_BITLENGTH) + count; + VALUE op = code[index]; + VALUE newop = func(data, op); + if (newop != op) { + code[index] = newop; + } + } + bits >>= 1; + count++; + } +} + static void rb_iseq_each_value(const rb_iseq_t *iseq, iseq_value_itr_t * func, void *data) { @@ -363,23 +384,13 @@ rb_iseq_each_value(const rb_iseq_t *iseq, iseq_value_itr_t * func, void *data) https://github.com/ruby/ruby/blob/trunk/iseq.c#L384 } // Embedded VALUEs - for (unsigned int i = 0; i < ISEQ_MBITS_BUFLEN(size); i++) { - iseq_bits_t bits = body->mark_offset_bits[i]; - if (bits) { - unsigned int count = 0; - - while(bits) { - if (bits & 0x1) { - unsigned int index = (i * ISEQ_MBITS_BITLENGTH) + count; - VALUE op = code[index]; - VALUE newop = func(data, op); - if (newop != op) { - code[index] = newop; - } - } - bits >>= 1; - count++; - } + if (ISEQ_MBITS_BUFLEN(size) == 1) { + iseq_scan_bits(0, body->mark_bits.single, code, func, data); + } + else { + for (unsigned int i = 0; i < ISEQ_MBITS_BUFLEN(size); i++) { + iseq_bits_t bits = body->mark_bits.list[i]; + iseq_scan_bits(i, bits, code, func, data); } } } diff --git a/vm_core.h b/vm_core.h index 5a6643674a..b7d980e0ec 100644 --- a/vm_core.h +++ b/vm_core.h @@ -465,7 +465,10 @@ struct rb_iseq_constant_body { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L465 unsigned int ivc_size; // Number of IVC and ICVARC caches unsigned int ci_size; unsigned int stack_max; /* for stack overflow check */ - iseq_bits_t * mark_offset_bits; /* Find references for GC */ + union { + iseq_bits_t * list; /* Find references for GC */ + iseq_bits_t single; + } mark_bits; char catch_except_p; /* If a frame of this ISeq may catch exception, set TRUE */ // If true, this ISeq is leaf *and* backtraces are not used, for example, -- cgit v1.2.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/