mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-13 17:20:21 +02:00
Add inline allocation for small objects for bdw-gc
This commit is contained in:
parent
d63288048c
commit
a654a790b9
1 changed files with 74 additions and 8 deletions
78
bdw.h
78
bdw.h
|
@ -15,20 +15,86 @@
|
|||
#define GC_NO_THREAD_REDIRECTS 1
|
||||
|
||||
#include <gc/gc.h>
|
||||
#include <gc/gc_inline.h> /* GC_generic_malloc_many */
|
||||
|
||||
struct context {};
|
||||
#define GC_INLINE_GRANULE_WORDS 2
|
||||
#define GC_INLINE_GRANULE_BYTES (sizeof(void *) * GC_INLINE_GRANULE_WORDS)
|
||||
|
||||
/* A freelist set contains GC_INLINE_FREELIST_COUNT pointers to singly
|
||||
linked lists of objects of different sizes, the ith one containing
|
||||
objects i + 1 granules in size. This setting of
|
||||
GC_INLINE_FREELIST_COUNT will hold freelists for allocations of
|
||||
up to 256 bytes. */
|
||||
#define GC_INLINE_FREELIST_COUNT (256U / GC_INLINE_GRANULE_BYTES)
|
||||
|
||||
struct context {
|
||||
void *freelists[GC_INLINE_FREELIST_COUNT];
|
||||
void *pointerless_freelists[GC_INLINE_FREELIST_COUNT];
|
||||
};
|
||||
|
||||
static inline size_t gc_inline_bytes_to_freelist_index(size_t bytes) {
|
||||
return (bytes - 1U) / GC_INLINE_GRANULE_BYTES;
|
||||
}
|
||||
static inline size_t gc_inline_freelist_object_size(size_t idx) {
|
||||
return (idx + 1U) * GC_INLINE_GRANULE_BYTES;
|
||||
}
|
||||
|
||||
// The values of these must match the internal POINTERLESS and NORMAL
|
||||
// definitions in libgc, for which unfortunately there are no external
|
||||
// definitions. Alack.
|
||||
enum gc_inline_kind {
|
||||
GC_INLINE_KIND_POINTERLESS,
|
||||
GC_INLINE_KIND_NORMAL
|
||||
};
|
||||
|
||||
static void* allocate_small_slow(void **freelist, size_t idx,
|
||||
enum gc_inline_kind kind) NEVER_INLINE;
|
||||
static void* allocate_small_slow(void **freelist, size_t idx,
|
||||
enum gc_inline_kind kind) {
|
||||
size_t bytes = gc_inline_freelist_object_size(idx);
|
||||
GC_generic_malloc_many(bytes, kind, freelist);
|
||||
void *head = *freelist;
|
||||
if (UNLIKELY (!head)) {
|
||||
fprintf(stderr, "ran out of space, heap size %zu\n",
|
||||
GC_get_heap_size());
|
||||
abort();
|
||||
}
|
||||
*freelist = *(void **)(head);
|
||||
return head;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
allocate_small(void **freelist, size_t idx, enum gc_inline_kind kind) {
|
||||
void *head = *freelist;
|
||||
|
||||
if (UNLIKELY (!head))
|
||||
return allocate_small_slow(freelist, idx, kind);
|
||||
|
||||
*freelist = *(void **)(head);
|
||||
return head;
|
||||
}
|
||||
|
||||
#define GC_HEADER /**/
|
||||
|
||||
static inline void* allocate(struct context *cx, enum alloc_kind kind,
|
||||
size_t size) {
|
||||
size_t idx = gc_inline_bytes_to_freelist_index(size);
|
||||
|
||||
if (UNLIKELY(idx >= GC_INLINE_FREELIST_COUNT))
|
||||
return GC_malloc(size);
|
||||
|
||||
return allocate_small(&cx->freelists[idx], idx, GC_INLINE_KIND_NORMAL);
|
||||
}
|
||||
|
||||
static inline void*
|
||||
allocate_pointerless(struct context *cx, enum alloc_kind kind,
|
||||
size_t size) {
|
||||
static inline void* allocate_pointerless(struct context *cx,
|
||||
enum alloc_kind kind, size_t size) {
|
||||
size_t idx = gc_inline_bytes_to_freelist_index(size);
|
||||
|
||||
if (UNLIKELY (idx >= GC_INLINE_FREELIST_COUNT))
|
||||
return GC_malloc_atomic(size);
|
||||
|
||||
return allocate_small(&cx->pointerless_freelists[idx], idx,
|
||||
GC_INLINE_KIND_POINTERLESS);
|
||||
}
|
||||
|
||||
static inline void collect(struct context *cx) {
|
||||
|
@ -56,14 +122,14 @@ static struct context* initialize_gc(size_t heap_size) {
|
|||
GC_expand_hp(heap_size - current_heap_size);
|
||||
}
|
||||
GC_allow_register_threads();
|
||||
return GC_malloc_atomic(1);
|
||||
return GC_malloc(sizeof(struct context));
|
||||
}
|
||||
|
||||
static struct context* initialize_gc_for_thread(uintptr_t *stack_base,
|
||||
struct context *parent) {
|
||||
struct GC_stack_base base = { stack_base };
|
||||
GC_register_my_thread(&base);
|
||||
return GC_malloc_atomic(1);
|
||||
return GC_malloc(sizeof(struct context));
|
||||
}
|
||||
static void finish_gc_for_thread(struct context *cx) {
|
||||
GC_unregister_my_thread();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue