diff --git a/src/copy-space.h b/src/copy-space.h index a863ca51a..e51f9f8ee 100644 --- a/src/copy-space.h +++ b/src/copy-space.h @@ -10,6 +10,7 @@ #include "assert.h" #include "debug.h" +#include "extents.h" #include "gc-align.h" #include "gc-attrs.h" #include "gc-inline.h" @@ -100,11 +101,6 @@ copy_space_object_region(struct gc_ref obj) { return (gc_ref_value(obj) / COPY_SPACE_REGION_SIZE) & 1; } -struct copy_space_extent { - uintptr_t low_addr; - uintptr_t high_addr; -}; - struct copy_space { struct copy_space_block *empty; struct copy_space_block *partly_full; @@ -119,8 +115,7 @@ struct copy_space { uint8_t atomic_forward; size_t allocated_bytes_at_last_gc; size_t fragmentation_at_last_gc; - struct copy_space_extent *extents; - size_t nextents; + struct extents *extents; struct copy_space_slab *slabs; size_t nslabs; }; @@ -542,11 +537,7 @@ copy_space_forward_if_traced(struct copy_space *space, struct gc_edge edge, static inline int copy_space_contains(struct copy_space *space, struct gc_ref ref) { - for (size_t i = 0; i < space->nextents; i++) - if (space->extents[i].low_addr <= gc_ref_value(ref) && - gc_ref_value(ref) < space->extents[i].high_addr) - return 1; - return 0; + return extents_contain_addr(space->extents, gc_ref_value(ref)); } static inline void @@ -607,10 +598,8 @@ copy_space_init(struct copy_space *space, size_t size, int atomic) { space->atomic_forward = atomic; space->allocated_bytes_at_last_gc = 0; space->fragmentation_at_last_gc = 0; - space->extents = calloc(1, sizeof(struct copy_space_extent)); - space->extents[0].low_addr = (uintptr_t) slabs; - space->extents[0].high_addr = space->extents[0].low_addr + reserved; - space->nextents = 1; + space->extents = extents_allocate(10); + extents_adjoin(space->extents, slabs, reserved); space->slabs = slabs; space->nslabs = nslabs; for (size_t slab = 0; slab < nslabs; slab++) { diff --git a/src/extents.h b/src/extents.h new file mode 100644 index 000000000..62dba92b9 --- /dev/null +++ b/src/extents.h @@ -0,0 +1,88 @@ +#ifndef EXTENTS_H +#define EXTENTS_H + +#include +#include + +#include "gc-assert.h" + +struct extent_range { + uintptr_t lo_addr; + uintptr_t hi_addr; +}; + +struct extents { + size_t size; + size_t capacity; + struct extent_range ranges[]; +}; + +static inline int +extents_contain_addr(struct extents *extents, uintptr_t addr) { + size_t lo = 0; + size_t hi = extents->size; + while (lo != hi) { + size_t mid = (lo + hi) / 2; + struct extent_range range = extents->ranges[mid]; + if (addr < range.lo_addr) { + hi = mid; + } else if (addr < range.hi_addr) { + return 1; + } else { + lo = mid + 1; + } + } + return 0; +} + +static struct extents* +extents_allocate(size_t capacity) { + size_t byte_size = + sizeof(struct extents) + sizeof(struct extent_range) * capacity; + struct extents *ret = malloc(byte_size); + if (!ret) __builtin_trap(); + memset(ret, 0, byte_size); + ret->capacity = capacity; + return ret; +} + +static struct extents* +extents_insert(struct extents *old, size_t idx, struct extent_range range) { + if (old->size < old->capacity) { + size_t bytes_to_move = sizeof(struct extent_range) * (old->size - idx); + memmove(&old->ranges[idx + 1], &old->ranges[idx], bytes_to_move); + old->ranges[idx] = range; + old->size++; + return old; + } else { + struct extents *new_ = extents_allocate(old->capacity * 2 + 1); + memcpy(&new_->ranges[0], &old->ranges[0], + sizeof(struct extent_range) * idx); + memcpy(&new_->ranges[idx + 1], &old->ranges[idx], + sizeof(struct extent_range) * (old->size - idx)); + new_->ranges[idx] = range; + new_->size = old->size + 1; + free(old); + return new_; + } +} + +static struct extents* +extents_adjoin(struct extents *extents, void *lo_addr, size_t size) { + size_t i; + struct extent_range range = { (uintptr_t)lo_addr, (uintptr_t)lo_addr + size }; + for (i = 0; i < extents->size; i++) { + if (range.hi_addr < extents->ranges[i].lo_addr) { + break; + } else if (range.hi_addr == extents->ranges[i].lo_addr) { + extents->ranges[i].lo_addr = range.lo_addr; + return extents; + } else if (range.lo_addr == extents->ranges[i].hi_addr) { + extents->ranges[i].hi_addr = range.hi_addr; + return extents; + } + } + return extents_insert(extents, i, range); +} + +#endif // EXTENTS_H