1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-11 00:00:49 +02:00

Refactor to allow "next" pointer embedded in block summary

This commit is contained in:
Andy Wingo 2022-05-19 22:05:09 +02:00
parent 7d80d45c79
commit 8f06b914b0

View file

@ -107,9 +107,34 @@ struct slab_header {
}; };
STATIC_ASSERT_EQ(sizeof(struct slab_header), HEADER_BYTES_PER_SLAB); STATIC_ASSERT_EQ(sizeof(struct slab_header), HEADER_BYTES_PER_SLAB);
// Sometimes we want to put a block on a singly-linked list. For that
// there's a pointer reserved in the block summary. But because the
// pointer is aligned (32kB on 32-bit, 64kB on 64-bit), we can portably
// hide up to 15 flags in the low bits. These flags can be accessed
// non-atomically by the mutator when it owns a block; otherwise they
// need to be accessed atomically.
enum block_summary_flag {
BLOCK_OUT_FOR_THREAD = 0x1,
BLOCK_HAS_PIN = 0x2,
BLOCK_PAGED_OUT = 0x4,
BLOCK_NEEDS_SWEEP = 0x8,
BLOCK_UNAVAILABLE = 0x10,
BLOCK_FLAG_UNUSED_5 = 0x20,
BLOCK_FLAG_UNUSED_6 = 0x40,
BLOCK_FLAG_UNUSED_7 = 0x80,
BLOCK_FLAG_UNUSED_8 = 0x100,
BLOCK_FLAG_UNUSED_9 = 0x200,
BLOCK_FLAG_UNUSED_10 = 0x400,
BLOCK_FLAG_UNUSED_11 = 0x800,
BLOCK_FLAG_UNUSED_12 = 0x1000,
BLOCK_FLAG_UNUSED_13 = 0x2000,
BLOCK_FLAG_UNUSED_14 = 0x4000,
};
struct block_summary { struct block_summary {
union { union {
struct { struct {
//struct block *next;
// Counters related to previous collection: how many holes there // Counters related to previous collection: how many holes there
// were, and how much space they had. // were, and how much space they had.
uint16_t hole_count; uint16_t hole_count;
@ -118,12 +143,12 @@ struct block_summary {
// wasted space due to fragmentation. // wasted space due to fragmentation.
uint16_t holes_with_fragmentation; uint16_t holes_with_fragmentation;
uint16_t fragmentation_granules; uint16_t fragmentation_granules;
// Status bytes. // After a block is swept, if it's empty it goes on the empties
uint8_t out_for_thread; // list. Otherwise if it's not immediately used by a mutator (as
uint8_t has_pin; // is usually the case), it goes on the swept list. Both of these
uint8_t paged_out; // lists use this field. But as the next element in the field is
uint8_t needs_sweep; // block-aligned, we stash flags in the low bits.
uint8_t unavailable; uintptr_t next_and_flags;
}; };
uint8_t padding[SUMMARY_BYTES_PER_BLOCK]; uint8_t padding[SUMMARY_BYTES_PER_BLOCK];
}; };
@ -172,6 +197,22 @@ static struct block_summary* block_summary_for_addr(uintptr_t addr) {
return (struct block_summary*) (base + block * sizeof(struct block_summary)); return (struct block_summary*) (base + block * sizeof(struct block_summary));
} }
static uintptr_t block_summary_has_flag(struct block_summary *summary,
enum block_summary_flag flag) {
return summary->next_and_flags & flag;
}
static void block_summary_set_flag(struct block_summary *summary,
enum block_summary_flag flag) {
summary->next_and_flags |= flag;
}
static void block_summary_clear_flag(struct block_summary *summary,
enum block_summary_flag flag) {
summary->next_and_flags &= ~(uintptr_t)flag;
}
static struct block* block_summary_next(struct block_summary *summary) {
return (struct block*) (summary->next_and_flags & ~(BLOCK_SIZE - 1));
}
static uintptr_t align_up(uintptr_t addr, size_t align) { static uintptr_t align_up(uintptr_t addr, size_t align) {
return (addr + align - 1) & ~(align-1); return (addr + align - 1) & ~(align-1);
} }
@ -779,13 +820,13 @@ static size_t next_hole(struct mutator *mut) {
if (!next_block(mut)) if (!next_block(mut))
return 0; return 0;
summary = block_summary_for_addr(mut->block); summary = block_summary_for_addr(mut->block);
} while (summary->unavailable); } while (block_summary_has_flag(summary, BLOCK_UNAVAILABLE));
if (!summary->needs_sweep) { if (!block_summary_has_flag(summary, BLOCK_NEEDS_SWEEP)) {
summary->hole_count++; summary->hole_count++;
summary->free_granules = GRANULES_PER_BLOCK; summary->free_granules = GRANULES_PER_BLOCK;
mut->alloc = mut->block; mut->alloc = mut->block;
mut->sweep = mut->block + BLOCK_SIZE; mut->sweep = mut->block + BLOCK_SIZE;
summary->needs_sweep = 1; block_summary_set_flag(summary, BLOCK_NEEDS_SWEEP);
return GRANULES_PER_BLOCK; return GRANULES_PER_BLOCK;
} }
mut->alloc = mut->sweep = mut->block; mut->alloc = mut->sweep = mut->block;
@ -976,7 +1017,8 @@ static int mark_space_init(struct mark_space *space, struct heap *heap) {
block--) { block--) {
if (size < heap->size) if (size < heap->size)
break; break;
space->slabs[nslabs-1].summaries[block].unavailable = 1; block_summary_set_flag(&space->slabs[nslabs-1].summaries[block],
BLOCK_UNAVAILABLE);
size -= BLOCK_SIZE; size -= BLOCK_SIZE;
} }
return 1; return 1;