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

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/

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