aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Hawthorn <john@hawthorn.email>2019-11-21 11:05:48 -0800
committerAaron Patterson <tenderlove@github.com>2019-11-22 12:42:24 -0800
commit8e743fad4e9124bd59bb5f14473cb188db9d3c34 (patch)
tree87f0c9f44b45c746ef45b5bf0c9ce9615f0200b2
parent26fd8d962ce42b7eb8d1c1eb43ddfa1ff24dc3aa (diff)
downloadruby-8e743fad4e9124bd59bb5f14473cb188db9d3c34.tar.gz
Count pinned slots using only bitmap
This is significantly faster than checking BUILTIN_TYPEs because we access significantly less memory. We also use popcount to count entire words at a time. The only functional difference from the previous implementation is that T_ZOMBIE objects will no longer be counted. However those are temporary objects which should be small in number, and this method has always been an estimate.
-rw-r--r--gc.c28
1 files changed, 4 insertions, 24 deletions
diff --git a/gc.c b/gc.c
index d2b4330889..9cc230bd3d 100644
--- a/gc.c
+++ b/gc.c
@@ -620,6 +620,7 @@ enum {
BITS_SIZE = sizeof(bits_t),
BITS_BITLENGTH = ( BITS_SIZE * CHAR_BIT )
};
+#define popcount_bits rb_popcount_intptr
struct heap_page_header {
struct heap_page *page;
@@ -7698,32 +7699,11 @@ init_cursors(rb_objspace_t *objspace, struct heap_cursor *free, struct heap_curs
static int
count_pinned(struct heap_page *page)
{
- RVALUE *pstart = page->start;
- RVALUE *pend = pstart + page->total_slots;
int pinned = 0;
+ int i;
- VALUE v = (VALUE)pstart;
- for (; v != (VALUE)pend; v += sizeof(RVALUE)) {
- void *poisoned = asan_poisoned_object_p(v);
- asan_unpoison_object(v, false);
-
- switch (BUILTIN_TYPE(v)) {
- case T_NONE:
- break;
- case T_ZOMBIE:
- pinned++;
- break;
- default:
- if (RVALUE_PINNED(v)) {
- pinned++;
- }
- break;
- }
-
- if (poisoned) {
- GC_ASSERT(BUILTIN_TYPE(v) == T_NONE);
- asan_poison_object(v);
- }
+ for (i = 0; i < HEAP_PAGE_BITMAP_LIMIT; i++) {
+ pinned += popcount_bits(page->pinned_bits[i]);
}
return pinned;